第八章 Matplotlib——绘制图形 ✨
Matplotlib 是 Python 数据科学生态中一颗璀璨的明星 🌟,它是创建各种静态、动态和交互式可视化图表的强大武器 🛠️。无论你是数据分析新手还是经验丰富的专家,Matplotlib 都能满足你的需求。
它具有以下闪光点:
注记
数据可视化是将抽象的数据以图形或图像的形式呈现出来,让数据更易于理解、分析和沟通。它就像一座桥梁,连接着冰冷的数据和人类的认知,让数据变得生动有趣。
注记
Python 数据科学生态系统是由一系列用于数据科学的 Python 库和工具组成的大家庭。这些成员各有所长,相互协作,为数据处理、分析、可视化和机器学习提供了强大的支持。其中,Numpy和Pandas是重要的组成部分。
Matplotlib 的绘图接口与 MATLAB 有着异曲同工之妙,这使得 MATLAB 用户可以轻松过渡到 Matplotlib。不过,它们之间也存在一些关键差异:
特性 | Matplotlib | MATLAB |
---|---|---|
语言 | Python | MATLAB |
类型 | 开源、免费 🆓 | 商业软件、收费 💰 |
扩展性 | 易于与其他 Python 库集成,拥有无限可能 ♾️ | 扩展性相对有限 |
社区支持 | 庞大的开源社区,活跃的开发者和用户群体,让你不再孤单 💪 | MathWorks 公司提供的官方支持和有限的社区资源 |
应用领域 | 数据科学、机器学习、科学计算、Web 开发等,无所不能 🚀 | 工程、科学计算、控制系统等 |
Matplotlib 图表由多个基本组件构成,它们共同支撑起整个可视化框架。
matplotlib.pyplot.figure()
创建。matplotlib.figure.Figure.add_axes()
创建。matplotlib.figure.Figure.add_subplot()
或 plt.subplots()
创建。注记
Figure (图形): 🖼️ 整个绘图区域,就像一块画布,你可以在上面尽情挥洒创意。它可以包含一个或多个 Axes。
matplotlib.pyplot.figure()
创建。注记
Axes (轴域): 📈 具有数据空间的图像区域,通常包含两个(二维)或三个(三维)坐标轴,它们定义了数据的范围和刻度。一个 Figure 可以包含多个 Axes,但一个 Axes 只能属于一个 Figure。
matplotlib.figure.Figure.add_axes()
创建。注记
Subplot (子图): 🧩 将 Figure 划分为多个子区域,每个子区域可以包含一个 Axes。这就像在画布上划分出多个小格子,每个格子都可以绘制不同的图表。
matplotlib.figure.Figure.add_subplot()
或 plt.subplots()
创建。让我们通过一个简单的例子来理解这些概念:
import matplotlib.pyplot as plt
:导入 matplotlib.pyplot
模块,并将其简称为 plt
。这是使用 Matplotlib 的标准做法。fig, axes = plt.subplots(2, 2)
:创建一个包含 2x2 个子图的 Figure,并将 Figure 对象赋值给 fig
,将 Axes 对象数组赋值给 axes
。axes
数组的形状是 (2, 2),可以通过 axes[0, 0]
、axes[0, 1]
、axes[1, 0]
、axes[1, 1]
分别访问每个子图。现在,让我们在每个子图中绘制不同的图表:
NumPy:Python 数值计算的基石 🧱
NumPy(Numerical Python)是 Python 科学计算的基础库,它提供了强大的 N 维数组对象 ndarray
,以及用于对数组进行高效操作的各种函数。NumPy 是数据分析、机器学习等领域不可或缺的工具。
np.random.randn(2, 50)
用于生成一个形状为 (2, 50) 的数组,其中的元素服从标准正态分布(均值为 0,标准差为 1)。
# 绘制饼图
labels = 'Taxi', 'Metro', 'Walk', 'Bus', 'Bicycle', 'Drive'
sizes = [10, 30, 5, 25, 5, 25]
explode = (0, 0.1, 0, 0, 0, 0) # 突出显示 "Metro"
axes[1, 1].pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90)
axes[1, 1].axis('equal') # 确保饼图是圆形的
axes[1, 1].set_title('Pie Chart')
plt.tight_layout() # 自动调整子图参数, 使之填充整个图像区域
plt.show()
Subplot
与 Axes
:兄弟情深 🤝Subplot
是 Axes
的子类,它们之间有着密切的关系。add_subplot()
方法实际上创建了一个 Axes
对象,并将其添加到 Figure
的子图网格中。Axes
提供了更丰富的方法来定制图表,例如设置坐标轴范围、添加标题、添加图例等。Subplot
与 Axes
:兄弟情深 🤝 - 代码解释注记
从上图可以看出,add_subplot()
方法返回的是 AxesSubplot
对象,它是 Axes
的子类。
Subplot
:一步到位 🎯除了使用 add_subplot()
方法外,还可以使用 matplotlib.pyplot.subplot()
方法直接创建一个 Subplot
并将其设置为当前活动的 Subplot
,这样后续的绘图操作都会在这个 Subplot
上进行。
Subplot
:一步到位 🎯Subplot
:一步到位 🎯 (续)提示
激活状态的图表:谁是主角? 🎬
在 Matplotlib 中,可以同时存在多个 Figure 和 Axes 对象。处于激活状态的 Figure 或 Axes 是指当前正在进行绘图操作的对象。可以使用 plt.gcf()
获取当前活动的 Figure,使用 plt.gca()
获取当前活动的 Axes。
Subplot
:一步到位 🎯 (续)Figure
的构成:细节决定成败 🔍一个 Figure
对象通常包含以下元素,它们共同构成了图表的完整信息:
所有这些元素都可以通过 Matplotlib 提供的接口进行修改,让你的图表更加个性化。
Matplotlib 提供了丰富的接口来修改图表的样式和添加装饰项,让你可以随心所欲地定制图表的外观,打造出独具风格的可视化作品。
plot()
函数的 linestyle
和 color
参数来控制线条的样式和颜色,让你的曲线更加生动。set_xticks()
、set_yticks()
、set_xticklabels()
和 set_yticklabels()
方法来控制坐标轴的刻度和标签,让你的图表更加清晰易读。text()
和 annotate()
方法在图表中添加文字注释,突出显示重要信息或添加解释说明。在上面的例子中,我们使用了 color
、linestyle
、linewidth
、marker
和 markersize
等参数来定制线条的样式。
color 参数值 |
含义 | linestyle 参数值 |
含义 |
---|---|---|---|
'r' |
红色 🔴 | '-' |
实线 |
'y' |
黄色 🟡 | '--' |
虚线 (短划线) |
'g' |
绿色 🟢 | '-.' |
点划线 |
'c' |
青色 🔵 | ':' |
虚线 (点) |
'b' |
蓝色 🔵 | ||
'm' |
紫红色 🟣 | ||
'w' |
白色 ⚪ | ||
'k' |
黑色 ⚫ |
import matplotlib.pyplot as plt
import numpy as np
fig, axe = plt.subplots()
# 绘制两条曲线(与上一个示例相同)
t = np.arange(0.0, 2.0, 0.01)
s = np.sin(2 * np.pi * t)
axe.plot(t, s, color='k', linestyle='-', label='Line 1')
s = np.sin(2 * np.pi * (t + 0.5))
axe.plot(t, s, color='c', linestyle='--', label='Line 2')
# 设置坐标轴刻度
axe.set_xticks(np.arange(0.0, 2.5, 0.5)) # 设置 x 轴刻度
axe.set_yticks([-1, 0, 1]) # 设置 y 轴刻度
plt.show()
axe.minorticks_on() # 显示 minor ticks
# 修改x轴刻度标签
axe.set_xticklabels(['零', '0.5', '壹', '1.5', '二'], fontproperties='SimHei') #设置中文字体
# 移动坐标轴
axe.spines['right'].set_color('none') # 隐藏右侧边框
axe.spines['top'].set_color('none') # 隐藏顶部边框
axe.spines['bottom'].set_position(('data', 0)) # 将 x 轴移动到 y=0 的位置
axe.spines['left'].set_position(('data', 0)) # 将 y 轴移动到 x=0 的位置
# 添加图例
axe.legend(loc='upper right', bbox_to_anchor=(1.25, 1.05))
plt.show()
在上面的例子中,我们使用了 set_xticks()
、set_yticks()
、minorticks_on()
、set_xticklabels()
和 spines
等方法来定制坐标轴的样式。我们还使用fontproperties='SimHei'
显示了中文标签。
text()
方法:在图表的指定位置添加文本,就像在画布上写字一样。
x
, y
: 文本的坐标,指定文本框左下角的位置。s
: 文本内容,可以是任何你想表达的信息。fontsize
: 字体大小,让你的文字更醒目。color
: 字体颜色,让你的文字更出彩。bbox
: 用于设置文本框的样式,如背景颜色、边框等,让你的文字更具个性。annotate()
方法:在图表的指定位置添加带箭头的注释,就像给图表中的某个点添加一个标注。
s
: 注释文本,说明你要标注的内容。xy
: 箭头指向的坐标,指定你要标注的点。xytext
: 注释文本的坐标,指定文本框的位置。arrowprops
: 用于设置箭头的样式,如颜色、箭头类型等,让你的标注更清晰。import matplotlib.pyplot as plt
import numpy as np
fig, axe = plt.subplots()
axe.plot(np.arange(0, 24, 2), [14, 9, 7, 5, 12, 19, 23, 26, 27, 24, 21, 19], '-o')
axe.set_xticks(np.arange(0, 24, 2))
# 添加箭头注释
axe.annotate('最高温度出现在 16:00', xy=(16, 27), xytext=(16, 22),
arrowprops=dict(facecolor='black', shrink=0.05, connectionstyle="arc3,rad=.2"), #箭头弯曲
horizontalalignment='center', verticalalignment='center')
plt.show()
在上面的例子中,我们使用了 annotate()
方法添加了一个带箭头的注释,指出了最高温度出现的时间。我们还使用了 text()
方法添加了一个文本注释,说明了数据的日期。
Matplotlib 提供了绘制各种常见图表类型的函数,就像一个百宝箱,里面装满了各种绘图工具,让你可以轻松应对不同的数据可视化需求。
hist()
): 显示数据分布的频数或频率,就像数据的“体检报告”。scatter()
): 显示两个变量之间的关系,就像探索数据“星座”的奥秘。pie()
): 显示各部分占总体的比例,就像切蛋糕一样,清晰展现数据的组成。bar()
): 比较不同类别的数据,就像数据的“身高”比拼。plot()
): 显示数据随时间变化的趋势,就像数据的“心电图”。table()
): 在图表中显示表格数据,让数据一目了然。直方图用于显示数据集中各个区间内数据值出现的频数或频率。通过直方图,我们可以大致了解数据集的分布情况,判断数据是否集中在某个区间,是否存在异常值等。
在上面的例子中,我们使用了 hist()
函数绘制了一个直方图。data
参数指定了要绘制的数据,bins
参数指定了柱子的数量。我们还使用了 color
和 edgecolor
参数来定制柱子的颜色和边框颜色。
我们可以在直方图上叠加一条正态分布密度曲线,以便更直观地观察数据的分布是否接近正态分布。
注记
这里补充说明一下正态分布的概率密度函数公式:
\[ f(x) = \frac{1}{\sigma\sqrt{2\pi}} e^{-\frac{1}{2}(\frac{x-\mu}{\sigma})^2} \]
其中:
standard_data = ((1 / (np.sqrt(2 * np.pi) * 1)) * np.exp(-0.5 * (1 / 1 * (bins - 0))**2))
这行代码就是根据上述公式计算标准正态分布(均值为 0,标准差为 1)在 bins
中每个点处的概率密度。
散点图用于显示两个变量之间的关系。将样本数据绘制在二维平面上,可以直观地显示这些点的分布情况,判断两个变量之间是否存在线性关系、非线性关系或其他关系。
在上面的例子中,我们使用了 scatter()
函数绘制了一个散点图。x
和 y
参数分别指定了散点的横坐标和纵坐标。我们还使用了 color
、marker
和 s
参数来定制散点的颜色、标记和大小。
scatter()
函数提供了丰富的参数来定制散点图中 Marker 的样式:
s
: Marker 的大小,可以是一个标量,也可以是一个数组,用于指定每个散点的大小。c
: Marker 的颜色,可以是一个颜色名称、RGB 值或 RGBA 值,也可以是一个数组,用于指定每个散点的颜色。alpha
: Marker 的透明度,取值范围为 0(完全透明)到 1(完全不透明)。marker
: Marker 的形状,可以是各种预定义的形状,如 'o'
(圆形)、's'
(方形)、'^'
(三角形) 等。import matplotlib.pyplot as plt
import numpy as np
# 生成随机数据
N = 60
np.random.seed(100)
x = np.random.rand(N)
y = np.random.rand(N)
s = np.pi * (10 * np.random.rand(N))**2 # 使用随机数生成 Marker 的大小
c = np.random.rand(N) # 使用随机数生成 Marker 的颜色
opacity = 0.7
# 绘制散点图
fig, axe = plt.subplots()
sc = axe.scatter(x, y, s, c, alpha=opacity, cmap='viridis') # 使用 cmap 参数指定颜色映射
plt.show()
在这个例子中,我们使用了 cmap='viridis'
,让散点的颜色根据 c
值在 viridis
颜色映射中变化。
饼图用于显示某一类别数据在全部样本数据中所占的百分比,就像切蛋糕一样,可以清晰地展现数据的组成。
import matplotlib.pyplot as plt
import numpy as np
# 准备数据
labels = 'Taxi', 'Metro', 'Walk', 'Bus', 'Bicycle', 'Drive'
sizes = [10, 30, 5, 25, 5, 25]
explode = (0, 0.1, 0, 0, 0, 0) # 突出显示 "Metro"
# 绘制饼图
fig, axe = plt.subplots()
axe.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90, colors=['skyblue', 'coral', 'lightgreen', 'gold', 'plum', 'lightsalmon']) # 设置每个扇形的颜色
axe.axis('equal') # 确保饼图是圆形的
axe.set_title('Pie Chart')
plt.show()
在上面的例子中,我们使用了 pie()
函数绘制了一个饼图。sizes
参数指定了每个扇形的大小,labels
参数指定了每个扇形的标签,explode
参数指定了要突出显示的扇形,autopct
参数指定了百分比的显示格式,shadow
参数指定了是否显示阴影,startangle
参数指定了起始角度。我们还使用了 colors
参数来定制每个扇形的颜色。
柱状图用于比较不同类别的数据,就像数据的“身高”比拼,可以直观地反映不同类别数据之间的数量差异。
import matplotlib.pyplot as plt
import numpy as np
# 准备数据
data_m = (40, 60, 120, 180, 20, 200) # 男性
data_f = (30, 100, 150, 30, 20, 50) # 女性
index = np.arange(6)
width = 0.35 # 柱子的宽度
labels = ('Taxi', 'Metro', 'Walk', 'Bus', 'Bicycle', 'Driving')
# 绘制柱状图
fig, axe = plt.subplots()
rects1 = axe.bar(index, data_m, width, color='skyblue', label='Men') # 男性柱子
plt.show()
rects2 = axe.bar(index + width, data_f, width, color='coral', label='Women') # 女性柱子
axe.set_xticks(index + width / 2)
axe.set_xticklabels(labels)
axe.legend()
# 添加数据标签
def autolabel(rects):
"""在每个柱形顶部添加数据标签"""
for rect in rects:
height = rect.get_height()
axe.annotate('{}'.format(height),
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3), # 3 points vertical offset
textcoords="offset points",
ha='center', va='bottom')
autolabel(rects1)
autolabel(rects2)
plt.show()
在上面的例子中,我们使用了 bar()
函数绘制了一个柱状图。index
参数指定了柱子的横坐标,data_m
和 data_f
参数分别指定了男性和女性柱子的高度,width
参数指定了柱子的宽度,color
参数指定了柱子的颜色,label
参数指定了柱子的标签。
我们可以在柱状图的基础上绘制堆叠柱状图,将不同类别的数据堆叠在一起,更清晰地展现数据的组成。
import matplotlib.pyplot as plt
import numpy as np
# 准备数据(与上一个示例相同)
data_m = (40, 60, 120, 180, 20, 200)
data_f = (30, 100, 150, 30, 20, 50)
index = np.arange(6)
width = 0.35
labels = ('Taxi', 'Metro', 'Walk', 'Bus', 'Bicycle', 'Driving')
# 绘制堆叠柱状图
fig, axe = plt.subplots()
axe.bar(index, data_m, width, color='skyblue', label='Men')
axe.bar(index, data_f, width, color='coral', bottom=data_m, label='Women') # 使用 bottom 参数堆叠柱形
axe.set_xticks(index + width / 2)
axe.set_xticklabels(labels)
axe.legend()
plt.show()
在上面的例子中,我们使用了 bottom
参数来指定堆叠柱状图的底部,将女性柱子堆叠在男性柱子之上。
我们还可以绘制并排柱状图或部分重叠柱状图,以不同的方式展示数据的对比。
import matplotlib.pyplot as plt
import numpy as np
# 准备数据(与上一个示例相同)
data_m = (40, 60, 120, 180, 20, 200)
data_f = (30, 100, 150, 30, 20, 50)
index = np.arange(6)
width = 0.4
labels = ('Taxi', 'Metro', 'Walk', 'Bus', 'Bicycle', 'Driving')
# 绘制并排柱状图
fig, axe = plt.subplots()
axe.bar(index - width/2, data_m, width, color='skyblue', align='center', label='Men') # 使用 align='center' 使柱形居中
axe.bar(index + width/2, data_f, width, color='coral', align='center', label='Women') # 使用 align='edge' 使柱形部分重叠
axe.set_xticks(index)
axe.set_xticklabels(labels)
axe.legend()
plt.show()
在上面的例子中,我们调整了柱子的横坐标和 align
参数,使得男性和女性的柱子并排显示。
我们还可以绘制水平柱状图,并添加透明度,让图表更具层次感。
import matplotlib.pyplot as plt
import numpy as np
# 准备数据(与上一个示例相同)
data_m = (40, 60, 120, 180, 20, 200)
data_f = (30, 100, 150, 30, 20, 50)
index = np.arange(6)
width = 0.35
opacity = 0.7 #设置透明度
labels = ('Taxi', 'Metro', 'Walk', 'Bus', 'Bicycle', 'Driving')
# 绘制水平柱状图
fig, axe = plt.subplots()
axe.barh(index, data_m, width, color='skyblue', align='center', alpha=opacity, label='Men') # 使用 barh() 绘制水平柱状图
plt.show()
在这个例子中,我们使用了 barh()
函数来绘制水平柱状图,并使用 alpha
参数设置了柱子的透明度。
折线图用于显示数据随时间变化的趋势,就像数据的“心电图”,可以清晰地展示数据的变化规律。
import matplotlib.pyplot as plt
import numpy as np
# 生成随机数据
np.random.seed(100)
x = np.arange(0, 10, 1)
y1 = np.random.rand(10)
y2 = np.random.rand(10)
# 绘制折线图
fig, axe = plt.subplots()
axe.plot(x, y1, '-o', color='skyblue', label='Line 1') # 使用 '-o' 绘制带圆点的实线
axe.plot(x, y2, '--o', color='coral', label='Line 2') # 使用 '--o' 绘制带圆点的虚线
axe.legend()
plt.show()
在上面的例子中,我们使用了 plot()
函数绘制了两条折线图。x
参数指定了横坐标,y1
和 y2
参数分别指定了两条折线的纵坐标。我们还使用了 '-o'
和 '--o'
来指定线型和标记,并使用 color
参数设置了线条颜色。
table()
函数可以在图表中显示表格数据,让数据更加清晰易读。
import matplotlib.pyplot as plt
import numpy as np
# 准备数据(与柱状图示例相同)
data_m = (40, 60, 120, 180, 20, 200)
data_f = (30, 100, 150, 30, 20, 50)
index = np.arange(6)
width = 0.4
columns = ('Taxi', 'Metro', 'Walk', 'Bus', 'Bicycle', 'Driving')
rows = ('Male', 'Female')
data = (data_m, data_f)
# 绘制柱状图(可选)
fig, axe = plt.subplots()
axe.bar(index, data_m, width, color='skyblue', label='Men')
axe.bar(index, data_f, width, color='coral', bottom=data_m, label='Women')
axe.set_xticks([]) # 隐藏 x 轴刻度
axe.legend()
# 添加表格
axe.table(cellText=data, rowLabels=rows, colLabels=columns, loc='bottom', bbox=[0, -0.5, 1, 0.3]) # 使用 bbox 参数调整表格位置
plt.show()
注记
上述代码中,bbox=[0, -0.5, 1, 0.3]
的含义是:
0
: 表格左边缘的 x 坐标(相对于 Axes 宽度)。-0.5
: 表格下边缘的 y 坐标(相对于 Axes 高度)。1
: 表格的宽度(相对于 Axes 宽度)。0.3
: 表格的高度(相对于 Axes 高度)。除了常见的平面直角坐标系外,Matplotlib 还支持在其他坐标系下绘制图像,例如极坐标系。
import matplotlib.pyplot as plt
import numpy as np
# 生成角度数据
theta_list = np.arange(0, 2 * np.pi, 0.01)
# 计算半径数据
r = [2 * np.cos(2 * theta) for theta in theta_list]
# 创建极坐标系
axe = plt.subplot(projection='polar') # 使用 projection='polar' 创建极坐标系
# 绘制双纽线
axe.plot(theta_list, r, color='skyblue', linewidth=2)
# 隐藏半径刻度
axe.set_rticks([])
plt.show()
在上面的例子中,我们首先使用 np.arange()
函数生成了一系列角度值,然后根据双纽线的极坐标方程计算了对应的半径值。接着,我们使用 plt.subplot(projection='polar')
创建了一个极坐标系,并使用 plot()
函数绘制了双纽线。最后,我们使用 set_rticks([])
隐藏了半径刻度。
除了二维图表外,Matplotlib 还提供了绘制三维图表的功能,让你可以从多个角度观察数据,发现更多隐藏的信息。
Axes3D
):星辰大海 ✨import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
# 生成随机数据
N = 60
np.random.seed(100)
x = np.random.rand(N)
y = np.random.rand(N)
z = np.random.rand(N)
# 创建 3D 坐标系
fig = plt.figure()
axe = Axes3D(fig, auto_add_to_figure=False) # 使用 Axes3D 创建 3D 坐标系
fig.add_axes(axe)
# 绘制 3D 散点图
axe.scatter(x, y, z, c='skyblue', marker='o')
# 设置坐标轴标签
axe.set_xlabel('X')
axe.set_ylabel('Y')
axe.set_zlabel('Z')
plt.show()
在上面的例子中,我们首先导入了 mpl_toolkits.mplot3d
中的 Axes3D
类。然后,我们使用 Axes3D(fig)
创建了一个三维坐标系,并使用 scatter()
函数绘制了三维散点图。最后,我们使用 set_xlabel()
、set_ylabel()
和 set_zlabel()
方法设置了坐标轴标签。 > 注意:在较新的matplotlib版本中,创建Axes3D对象时,需要设置auto_add_to_figure=False
参数,并手动将Axes3D对象添加到figure中。
Axes3D
):星辰大海 ✨pyplot
):殊途同归 🎯除了使用 Axes3D
类外,我们还可以直接使用 pyplot
模块的 subplot()
函数,并指定 projection='3d'
来创建三维坐标系。
import matplotlib.pyplot as plt
import numpy as np
# 生成随机数据(与上一个示例相同)
N = 60
np.random.seed(100)
x = np.random.rand(N)
y = np.random.rand(N)
z = np.random.rand(N)
# 创建 3D 坐标系
fig = plt.figure()
axe = plt.subplot(projection='3d') # 使用 projection='3d' 创建 3D 坐标系
# 绘制 3D 散点图
axe.scatter(x, y, z, c='coral', marker='^') # 使用不同的颜色和标记
# 设置坐标轴标签
axe.set_xlabel('X')
axe.set_ylabel('Y')
axe.set_zlabel('Z')
plt.show()
pyplot
):殊途同归 🎯将 Matplotlib 与 Jupyter Notebook 结合使用,可以方便地创建图文并茂、格式精美的文档,让你的数据分析更上一层楼。
提示
文档组成部分 - Markdown Cell: 用于编写文本内容、介绍双纽线的概念、公式和绘图方法。 - Code Cell: 用于编写 Python 代码,生成双纽线的图像。
邱飞 💌 [email protected]