第 9 章:绘图与可视化
生成信息丰富的可视化图形(有时称为图表)是数据分析中最重要的任务之一。
Note
Python 有许多用于可视化的附加库,但我们将重点关注 matplotlib 以及构建在其之上的库,例如 seaborn。
Tip
Matplotlib 催生了像 seaborn 这样的附加工具包,增强了其功能。
要在 Jupyter Notebook 中以内联方式显示图表,请使用魔术命令:
Note
此命令告诉 Jupyter 直接在笔记本输出中显示 matplotlib 图表。没有它,您可能看不到您的图表!
Tip
这里学到的原则可以适用于其他可视化库。
matplotlib 的导入惯例:
Note
这行代码从 matplotlib
导入 pyplot
模块,并给它一个更短的名称 plt
。这是一种常见的做法,可以使您的代码更简洁易读。
np.arange(10)
:创建一个从 0 到 9 的数字数组。plt.plot(data)
:将数据绘制为折线图。matplotlib 中的图表位于 Figure 对象中。
使用 plt.figure()
创建一个新图形:
plt.figure
选项:
figsize
:保证图形大小和纵横比。add_subplot
创建子图:add_subplot(2, 2, 1)
表示:
Note
在 Jupyter Notebook 中,图表在每个单元格后重置。将所有绘图命令放在一个单元格中。
plt.plot
等顶级函数。<matplotlib.lines.Line2D at ...>
的输出。
;
)。
ax1.hist(np.random.standard_normal(100), bins=20, color="black", alpha=0.3)
# 在第一个子图(ax1)上创建一个直方图。
# np.random.standard_normal(100)生成100个标准正态分布的随机数。
# bins=20将数据分成20个柱子。
# color="black"设置柱子颜色为黑色。
# alpha=0.3设置透明度为0.3。
ax2.scatter(np.arange(30), np.arange(30) + 3 * np.random.standard_normal(30))
# 在第二个子图(ax2)上创建一个散点图。
# np.arange(30)创建从0到29的整数数组作为x坐标。
# np.arange(30) + 3 * np.random.standard_normal(30)创建y坐标,其中加入了一些随机噪声。
ax1.hist(...)
:创建直方图。ax2.scatter(...)
:创建散点图。alpha=0.3
:设置图表的透明度。plt.subplots
方便地创建子图plt.subplots
创建一个图形和一个包含子图对象的 NumPy 数组:axes[0, 1]
。sharex
和 sharey
:共享相同的 x 轴或 y 轴以比较数据。plt.subplots
选项 ⚙️参数 | 描述 |
---|---|
nrows |
子图的行数 |
ncols |
子图的列数 |
sharex |
所有子图使用相同的 x 轴刻度 |
sharey |
所有子图使用相同的 y 轴刻度 |
subplot_kw |
传递给 add_subplot 的关键字字典 |
**fig_kw |
传递给 subplots 的其他关键字(例如,figsize=(8, 6) ) |
表 9-1. matplotlib.pyplot.subplots
选项
subplots_adjust
方法更改间距:wspace
和 hspace
:控制用于间距的图形宽度/高度的百分比。"#CECECE"
)。plt.plot
文档字符串(使用 plt.plot?
)。drawstyle
选项 🎨drawstyle
选项更改:drawstyle
选项的折线图xlim
、xticks
、xticklabels
:控制图表范围、刻度位置和标签。ax.xlim()
)。ax.xlim([0, 10])
)。xticks
的简单图表xticks
的简单图表rotation
:设置刻度标签旋转(例如,30 度)。set_xlabel
:命名 x 轴。set_title
:设置子图标题。set
方法:label
参数:fig, ax = plt.subplots() # 创建一个包含一个子图的图形
ax.plot(np.random.randn(1000).cumsum(), color="black", label="one")
# 绘制第一条线,标签为"one"。
ax.plot(np.random.randn(1000).cumsum(), color="black", linestyle="dashed", label="two")
# 绘制第二条线,标签为"two",线型为虚线。
ax.plot(np.random.randn(1000).cumsum(), color="black", linestyle="dotted", label="three")
# 绘制第三条线,标签为"three",线型为点线。
ax.legend() # 显示图例
ax.legend()
选项 ⚙️ax.legend()
:自动创建图例。loc
:指定图例位置(默认为 "best"
)。label="_nolegend_"
。text
、arrow
、annotate
函数。ax.text(x, y, "Hello world!", family="monospace", fontsize=10)
:在 (x, y) 处绘制文本。import pandas as pd # 导入pandas库
from datetime import datetime # 导入datetime模块
fig, ax = plt.subplots() # 创建一个图形和一个子图
data = pd.read_csv("examples/spx.csv", index_col=0, parse_dates=True)
# 从CSV文件读取数据。
# index_col=0将第一列设置为索引。
# parse_dates=True尝试将索引解析为日期。
spx = data["SPX"] # 获取"SPX"列(标准普尔500指数)
spx.plot(ax=ax, color="black") # 绘制标准普尔500指数,颜色为黑色
crisis_data = [
(datetime(2007, 10, 11), "Peak of bull market"), # 牛市高峰
(datetime(2008, 3, 12), "Bear Stearns Fails"), # 贝尔斯登倒闭
(datetime(2008, 9, 15), "Lehman Bankruptcy") # 雷曼兄弟破产
]
for date, label in crisis_data: # 遍历危机数据
ax.annotate(label, xy=(date, spx.asof(date) + 75),
xytext=(date, spx.asof(date) + 225),
arrowprops=dict(facecolor="black", headwidth=4, width=2,
headlength=4),
horizontalalignment="left", verticalalignment="top")
# 使用ax.annotate()添加注释。
# label: 注释文本。
# xy: 箭头指向的坐标(x, y)。
# xytext: 文本的起始坐标。
# arrowprops: 箭头属性(颜色、头部宽度、箭头宽度、头部长度)。
# horizontalalignment, verticalalignment: 文本对齐方式。
ax.annotate
:在指定的 (x, y) 坐标处绘制标签。set_xlim
、set_ylim
:手动设置图表边界。ax.set_title
:添加主标题。Rectangle
、Circle
:在 matplotlib.pyplot
中找到。matplotlib.patches
。ax.add_patch
添加到图表。fig, ax = plt.subplots() # 创建一个图形和一个子图
rect = plt.Rectangle((0.2, 0.75), 0.4, 0.15, color="black", alpha=0.3)
# 创建一个矩形对象。
# (0.2, 0.75): 左下角坐标。
# 0.4: 宽度。
# 0.15: 高度。
# color="black": 颜色为黑色。
# alpha=0.3: 透明度为0.3。
circ = plt.Circle((0.7, 0.2), 0.15, color="blue", alpha=0.3)
# 创建一个圆形对象。
# (0.7, 0.2): 圆心坐标。
# 0.15: 半径。
# color="blue": 颜色为蓝色。
# alpha=0.3: 透明度为0.3。
pgon = plt.Polygon([[0.15, 0.15], [0.35, 0.4], [0.2, 0.6]],
color="green", alpha=0.5)
# 创建一个多边形对象。
# [[0.15, 0.15], [0.35, 0.4], [0.2, 0.6]]: 多边形顶点坐标。
# color="green": 颜色为绿色。
# alpha=0.5: 透明度为0.5。
ax.add_patch(rect) # 将矩形添加到子图
ax.add_patch(circ) # 将圆形添加到子图
ax.add_patch(pgon) # 将多边形添加到子图
savefig
实例方法:保存活动图形。.pdf
、.png
)。dpi
:控制每英寸点数分辨率。savefig
选项 ⚙️参数 | 描述 |
---|---|
fname |
文件路径或 Python 类文件对象;格式从扩展名推断 |
dpi |
每英寸点数分辨率 |
facecolor |
子图外部的图形背景颜色(默认值:"w" - 白色) |
edgecolor |
图形边缘的颜色 |
format |
显式文件格式(例如,"png" 、"pdf" 、"svg" ) |
表 9-2. 部分 fig.savefig
选项
rc
方法:以编程方式修改配置。plt.rcParams
字典。plt.rcdefaults()
。rc
参数:要自定义的组件(例如,"figure"
、"axes"
、"xtick"
)。matplotlibrc
配置文件 📝matplotlib/mpl-data
中的 matplotlibrc
文件。matplotlibrc
放在您的主目录中,命名为 .matplotlibrc
。DataFrame
和 Series
对象的内置方法。Series
和 DataFrame
有一个 plot
属性。plot()
默认创建折线图:use_index=False
禁用)。xticks
、xlim
、yticks
、ylim
:调整轴刻度和限制。Series.plot
方法参数 ⚙️参数 | 描述 |
---|---|
label |
图例标签 |
ax |
要绘制的 matplotlib 子图对象 |
style |
样式字符串(例如,"ko--" ) |
alpha |
图表填充不透明度(0 到 1) |
kind |
图表类型:"area" 、"bar" 、"barh" 、"density" 、"hist" 、"kde" 、"line" 、"pie" |
figsize |
图形对象的大小 |
logx |
x 轴上的对数缩放 |
logy |
y 轴上的对数缩放 |
title |
图表标题 |
use_index |
使用对象索引作为刻度标签 |
rot |
刻度标签旋转(0-360) |
xticks |
x 轴刻度值 |
yticks |
y 轴刻度值 |
xlim |
x 轴限制(例如,[0, 10] ) |
ylim |
y 轴限制 |
grid |
显示轴网格(默认关闭) |
表 9-3. Series.plot
方法参数
ax
参数,用于指定 matplotlib 子图对象。df = pd.DataFrame(np.random.standard_normal((10, 4)).cumsum(0),
columns=["A", "B", "C", "D"],
index=np.arange(0, 100, 10))
# 创建一个DataFrame对象。
# np.random.standard_normal((10, 4)).cumsum(0): 生成10x4的标准正态分布随机数,并沿列(axis=0)计算累积和。
# columns=["A", "B", "C", "D"]: 设置列名为A, B, C, D。
# index=np.arange(0, 100, 10): 设置索引为0, 10, 20, ..., 90。
plt.style.use('grayscale') # 使用灰度样式,以适应黑白出版物
df.plot() # 绘制DataFrame的折线图,每列一条线
df.plot()
等同于 df.plot.line()
.DataFrame.plot
选项 ⚙️参数 | 描述 |
---|---|
subplots |
在单独的子图中绘制每个 DataFrame 列 |
layout |
2 元组(行、列),用于子图布局 |
sharex |
如果 subplots=True ,共享 x 轴刻度和限制 |
sharey |
如果 subplots=True ,共享 y 轴 |
legend |
添加子图图例(默认为 True) |
sort_columns |
按字母顺序绘制列(默认值:使用现有顺序) |
表 9-4. DataFrame
特定的图表参数
plot.bar()
: 垂直条形图。plot.barh()
: 水平条形图。fig, axes = plt.subplots(2, 1) # 创建一个包含2行1列子图的图形
data = pd.Series(np.random.uniform(size=16), index=list("abcdefghijklmnop"))
# 创建一个Series对象。
# np.random.uniform(size=16): 生成16个均匀分布的随机数。
# index=list("abcdefghijklmnop"): 设置索引为字母a到p。
data.plot.bar(ax=axes[0], color="black", alpha=0.7)
# 在第一个子图(axes[0])上绘制垂直条形图。
# color="black": 设置条形颜色为黑色。
# alpha=0.7: 设置透明度为0.7。
df = pd.DataFrame(np.random.uniform(size=(6, 4)),
index=["one", "two", "three", "four", "five", "six"],
columns=pd.Index(["A", "B", "C", "D"], name="Genus"))
# 创建一个DataFrame对象。
# np.random.uniform(size=(6, 4)): 生成6x4的均匀分布随机数。
# index=["one", "two", "three", "four", "five", "six"]: 设置行索引。
# columns=pd.Index(["A", "B", "C", "D"], name="Genus"): 设置列索引,并命名为"Genus"。
df.plot.bar() # 绘制DataFrame的条形图,每行的数据并排显示
stacked=True
: 创建堆叠条形图。read_csv
: 加载数据。crosstab
: 按天和聚会规模进行交叉表计算。# 删除1人和6人的聚会
party_counts = party_counts.loc[:, 2:5]
# 通过标签进行选择,此处选择列标签从2到5(包括)的列,即聚会规模为2、3、4和5的数据。
# 归一化,使每行的和为1
party_pcts = party_counts.div(party_counts.sum(axis="columns"), axis="index")
# 计算每个聚会规模占当天总聚会数的百分比。
# party_counts.sum(axis="columns"): 计算每行的总和。
# .div(): 执行除法,将每行的每个元素除以该行的总和。
# axis="index": 指定除法运算按行进行。
party_pcts.plot.bar(stacked=True) # 绘制堆叠条形图,展示每个聚会规模占当天总聚会数的百分比
import seaborn as sns # 导入seaborn库
tips["tip_pct"] = tips["tip"] / (tips["total_bill"] - tips["tip"])
# 添加一列"tip_pct",计算小费百分比。
sns.barplot(x="tip_pct", y="day", data=tips, orient="h")
# 使用seaborn的barplot绘制条形图。
# x="tip_pct": x轴使用"tip_pct"列的数据。
# y="day": y轴使用"day"列的数据。
# data=tips: 数据来源为tips DataFrame。
# orient="h": 水平显示条形图。
data
: pandas DataFrame。tip_pct
的平均值。seaborn.barplot
中的 hue
选项:按另一个分类值拆分。seaborn.set_style
:在图表外观之间切换。plot.hist
:创建直方图。plot.density
:创建密度图。Note
密度图需要 SciPy: conda install scipy
histplot
📊histplot
:同时绘制直方图和连续密度估计。comp1 = np.random.standard_normal(200) # 生成200个标准正态分布的随机数
comp2 = 10 + 2 * np.random.standard_normal(200) # 生成200个均值为10、标准差为2的正态分布随机数
values = pd.Series(np.concatenate([comp1, comp2])) # 将两个数组连接起来,并转换为Series对象
sns.histplot(values, bins=100, color="black")
# 使用seaborn的histplot绘制直方图和密度估计。
# bins=100: 将数据分成100个柱子。
# color="black": 设置颜色为黑色。
regplot
📈regplot
:绘制散点图并拟合线性回归线。seaborn.pairplot
:创建配对图。plot_kws
参数 ⚙️seaborn.pairplot
文档字符串了解详细信息。seaborn.catplot
:简化分面图。sns.catplot(x="day", y="tip_pct", hue="time", col="smoker",
kind="bar", data=tips[tips.tip_pct < 1])
# 使用seaborn的catplot创建分面条形图。
# x="day": x轴使用"day"列的数据。
# y="tip_pct": y轴使用"tip_pct"列的数据。
# hue="time": 根据"time"列的值对条形图进行着色区分。
# col="smoker": 根据"smoker"列的值将图表分成不同的列。
# kind="bar": 图表类型为条形图。
# data=tips[tips.tip_pct < 1]: 数据来源为tips DataFrame中"tip_pct"小于1的行。
catplot
的其他图表类型 📊catplot
支持其他图表类型(例如,箱线图)。seaborn.FacetGrid
🧩```markdown - 专注于 Web 交互式图形:Altair、Bokeh、Plotly。 - 对于静态图形:使用 matplotlib 和基于它构建的库(pandas、seaborn)。
Series
和 DataFrame
对象。邱飞 💌 [email protected]