Matplotlib 数据可视化基础教程:从入门到精通
数据是现代科学、商业和研究的基石。然而,原始的数据往往是枯燥、难以理解的。数据可视化是将复杂的数据转换成易于理解的图形或图表的过程,它能帮助我们发现数据中的模式、趋势和异常,从而做出更明智的决策。在 Python 的数据科学生态系统中,Matplotlib 是一个强大且灵活的数据可视化库,它是许多其他高级可视化库(如 Seaborn, Pandas 的内置绘图功能)的基础。
本教程将带领你从零开始,逐步掌握 Matplotlib 的基本用法,包括创建不同类型的图表、定制图表元素以及如何组织多个图表。无论你是数据分析新手还是希望巩固基础的开发者,本教程都将为你提供扎实的 Matplotlib 基础。
1. Matplotlib 简介与安装
什么是 Matplotlib?
Matplotlib 是一个用于创建静态、交互式和动画可视化的 Python 库。它的设计灵感来源于 MATLAB,因此对于熟悉 MATLAB 绘图的用户来说,上手 Matplotlib 会非常快。它支持广泛的绘图类型,从简单的线图、散点图到复杂的3D图和金融图表,几乎无所不能。
为什么选择 Matplotlib?
- 强大与灵活: 提供对图表每个元素的细粒度控制。
- 广泛的应用: 在科学研究、工程、数据分析等领域被广泛使用。
- 良好的文档和社区支持: 遇到问题时容易找到解决方案。
- 可扩展性: 可以与其他库(如 NumPy, Pandas)无缝集成。
安装 Matplotlib
安装 Matplotlib 非常简单,通常只需要使用 pip 包管理器。确保你已经安装了 Python。
打开终端或命令行,运行以下命令:
bash
pip install matplotlib
为了更方便地进行数据处理,我们通常也会同时安装 NumPy:
bash
pip install numpy
安装完成后,你就可以在 Python 脚本或 Jupyter Notebook 中导入并使用 Matplotlib 了。
2. Matplotlib 的核心概念:Figure 和 Axes
在开始绘图之前,理解 Matplotlib 的两个核心对象至关重要:Figure
(图)和 Axes
(坐标系或子图)。
- Figure (plt.Figure): Figure 是最高级别的容器,相当于一个窗口或一张画布。你可以在一个 Figure 中包含一个或多个 Axes。Figure 对象负责管理整个图表的属性,如大小、分辨率、标题等。
- Axes (matplotlib.axes.Axes): Axes 是 Figure 中的一个区域,用于实际绘制数据。它包含了 x 轴、y 轴(对于2D图表)、数据点、标签、图例、标题等所有绘图元素。一个 Figure 可以包含多个 Axes,每个 Axes 都是一个独立的绘图区域(即一个子图)。
理解 Figure 和 Axes 的关系是掌握 Matplotlib 精髓的关键。Matplotlib 提供了两种主要的绘图接口:
- Pyplot 接口 (State-based interface): 使用
matplotlib.pyplot
模块(通常导入为plt
)。这个接口提供了一系列函数,可以直接创建 Figure 和 Axes,并在当前活跃的 Axes 上进行绘制。这对于快速绘制简单的图表非常方便,但对于复杂的图表布局和定制,控制性稍弱。 - 面向对象接口 (Object-oriented interface): 显示地创建 Figure 和 Axes 对象,然后调用这些对象的方法进行绘图和定制。这种方式更加灵活和强大,尤其是在处理多个子图时。推荐在大多数情况下使用这种接口。
本教程将主要侧重于面向对象接口,因为它更能体现 Matplotlib 的强大之处。但我们也会先从简单的 Pyplot 接口入门。
3. 第一个 Matplotlib 图表:线图
让我们从绘制一个简单的线图开始。
“`python
import matplotlib.pyplot as plt
import numpy as np
使用 Pyplot 接口快速绘图
生成一些数据
x = np.linspace(0, 10, 100) # 在0到10之间生成100个点
y = np.sin(x) # 计算这些点的正弦值
绘制线图
plt.plot(x, y)
添加标题和轴标签 (使用 Pyplot 接口)
plt.title(“Simple Sine Wave”)
plt.xlabel(“X-axis”)
plt.ylabel(“Y-axis”)
显示图表
plt.show()
“`
运行这段代码,会弹出一个窗口或在 Notebook 中显示一张图,展示了一个正弦波。
现在,我们用面向对象接口来做同样的事情,并介绍 Figure 和 Axes 的概念。
“`python
import matplotlib.pyplot as plt
import numpy as np
生成一些数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
1. 创建 Figure 和 Axes 对象 (推荐方式)
fig 是 Figure 对象, ax 是 Axes 对象
plt.subplots() 是一个方便的函数,它会自动创建一个 Figure 和一个 Axes
fig, ax = plt.subplots()
2. 在 Axes 对象上绘制数据
ax.plot(x, y)
3. 设置 Axes 的属性 (使用 Axes 对象的方法)
ax.set_title(“Simple Sine Wave (OO Interface)”)
ax.set_xlabel(“X-axis”)
ax.set_ylabel(“Y-axis”)
4. 显示图表
plt.show()
“`
这段代码的效果与之前相同,但使用了面向对象的方法。plt.subplots()
返回一个 Figure 对象和一个 Axes 对象(或者在创建多个子图时返回一个 Axes 对象的数组)。然后,所有的绘图和定制操作都通过调用 ax
对象的方法来完成,例如 ax.plot()
, ax.set_title()
, ax.set_xlabel()
, ax.set_ylabel()
等。
为什么推荐面向对象接口?
- 更清晰的结构: 你知道你在哪个 Axes 上进行操作。
- 更容易管理多个子图: 当你需要创建复杂的图表布局时,面向对象接口提供了更直观的方式来访问和操作每个子图。
- 避免状态混乱: Pyplot 接口隐式地管理“当前”的 Figure 和 Axes,这在复杂的脚本中可能导致意外的行为。面向对象接口则避免了这种问题。
从现在开始,我们将主要使用面向对象接口 (fig, ax = plt.subplots()
) 进行讲解。
4. 定制线图
线图是展示数据趋势的常用方式。我们可以通过设置颜色、线型、标记等属性来定制线图。
“`python
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 50) # 减少点的数量,方便看标记
y1 = np.sin(x)
y2 = np.cos(x)
fig, ax = plt.subplots(figsize=(8, 5)) # 可以设置 Figure 的大小
绘制第一条线:红色虚线,圆形标记
ax.plot(x, y1, color=’red’, linestyle=’–‘, marker=’o’, label=’Sine’)
绘制第二条线:蓝色点划线,方形标记
ax.plot(x, y2, color=’blue’, linestyle=’-.’, marker=’s’, label=’Cosine’)
添加标题和轴标签
ax.set_title(“Sine and Cosine Waves”)
ax.set_xlabel(“X-axis”)
ax.set_ylabel(“Amplitude”)
添加图例 (必须在 plot 中设置 label 参数才能显示)
ax.legend()
添加网格线
ax.grid(True)
设置轴的显示范围
ax.set_xlim(-1, 11)
ax.set_ylim(-1.5, 1.5)
plt.show()
“`
常用定制参数:
color
: 设置线条颜色 (如'red'
,'blue'
,'green'
, 或十六进制颜色码#FF0000
)linestyle
: 设置线型 (如'-'
实线,'--'
虚线,'-.'
点划线,':'
点线)marker
: 设置数据点的标记样式 (如'o'
圆形,'s'
方形,'^'
三角形,'*'
星形)linewidth
: 设置线宽markersize
: 设置标记大小alpha
: 设置透明度 (0到1之间的浮点数)label
: 设置图例中的标签文本
5. 绘制不同类型的图表
除了线图,Matplotlib 支持多种常用的图表类型。下面介绍几种常见的:
5.1 散点图 (Scatter Plot)
散点图用于显示两个变量之间的关系,每个点代表一个观测值。
“`python
import matplotlib.pyplot as plt
import numpy as np
生成一些随机数据
np.random.seed(0) # 设置随机种子,确保结果可复现
x = np.random.rand(50) * 10
y = np.random.rand(50) * 10
colors = np.random.rand(50) # 颜色值
sizes = (np.random.rand(50) * 20) ** 2 # 点的大小
fig, ax = plt.subplots(figsize=(7, 7))
绘制散点图
s: size, c: color, alpha: transparency
scatter = ax.scatter(x, y, c=colors, s=sizes, alpha=0.6, cmap=’viridis’) # cmap设置颜色映射
ax.set_title(“Scatter Plot with Varying Size and Color”)
ax.set_xlabel(“Feature 1”)
ax.set_ylabel(“Feature 2”)
添加颜色条 (对于连续颜色映射很有用)
fig.colorbar(scatter, label=’Color Value’)
plt.show()
“`
ax.scatter()
函数的参数 s
控制点的大小,c
控制点的颜色。c
可以是一个单一颜色,也可以是一个与 x
、y
长度相同的数组,表示每个点的颜色。如果 c
是一个数值数组,通常会结合 cmap
参数设置颜色映射。
5.2 柱状图 (Bar Chart)
柱状图用于比较不同类别的数据。
“`python
import matplotlib.pyplot as plt
import numpy as np
categories = [‘A’, ‘B’, ‘C’, ‘D’, ‘E’]
values = np.array([25, 40, 30, 35, 20])
fig, ax = plt.subplots(figsize=(6, 4))
绘制垂直柱状图
ax.bar(categories, values, color=’skyblue’)
ax.set_title(“Bar Chart of Categories”)
ax.set_xlabel(“Category”)
ax.set_ylabel(“Value”)
可以在柱子上方添加数值标签 (可选)
for i, value in enumerate(values):
ax.text(i, value + 1, str(value), ha=’center’, va=’bottom’)
plt.show()
“`
ax.bar()
绘制垂直柱状图。如果你想绘制水平柱状图,可以使用 ax.barh(categories, values)
。对于水平柱状图,x 轴和 y 轴的含义会互换。
绘制分组柱状图或堆叠柱状图稍微复杂一些,需要调整柱子的位置或堆叠数值,但核心仍然是使用 ax.bar()
或 ax.barh()
。
5.3 直方图 (Histogram)
直方图用于显示数据的分布情况,将数据分成若干个区间(bins),然后统计每个区间内数据的频数。
“`python
import matplotlib.pyplot as plt
import numpy as np
生成一些随机数据 (正态分布)
data = np.random.randn(1000)
fig, ax = plt.subplots(figsize=(7, 5))
绘制直方图
bins: 区间的数量或区间的边界
edgecolor: 柱子边缘的颜色
ax.hist(data, bins=30, color=’lightgreen’, edgecolor=’black’)
ax.set_title(“Histogram of Random Data”)
ax.set_xlabel(“Value”)
ax.set_ylabel(“Frequency”)
plt.show()
“`
ax.hist()
函数的 bins
参数非常重要,它决定了直方图的粒度。bins
可以是一个整数,表示将数据分成多少个等宽的区间;也可以是一个序列,表示区间的具体边界。
5.4 饼图 (Pie Chart)
饼图用于显示各部分占总体的比例。
“`python
import matplotlib.pyplot as plt
labels = [‘Apples’, ‘Bananas’, ‘Cherries’, ‘Dates’]
sizes = [15, 30, 45, 10] # 各部分占总体的比例 (总和不必是100,Matplotlib会自动计算)
colors = [‘gold’, ‘yellowgreen’, ‘lightcoral’, ‘lightskyblue’]
explode = (0, 0.1, 0, 0) # ‘Bananas’ 部分突出显示
fig, ax = plt.subplots(figsize=(6, 6)) # 饼图通常需要设置为正方形以避免变形
绘制饼图
ax.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct=’%1.1f%%’, shadow=True, startangle=140) # autopct显示百分比,shadow显示阴影,startangle起始角度
让饼图看起来是圆的 (而不是椭圆)
ax.axis(‘equal’)
ax.set_title(“Distribution of Fruits”)
plt.show()
“`
ax.pie()
函数的 autopct
参数允许你在饼图上显示百分比。%1.1f%%
格式字符串表示保留一位小数并加上百分号。explode
参数是一个与数据长度相同的序列,用于指定哪些部分需要“爆炸”(即突出显示)。
6. 组织多个图表:子图 (Subplots)
在同一 Figure 中显示多个相关的图表(子图)是一种常见的需求,可以方便地进行比较。Matplotlib 提供了 plt.subplots()
函数来创建包含多个 Axes 的 Figure。
“`python
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = x
y4 = x**2
创建一个 2×2 的子图网格
fig 是 Figure 对象, axes 是一个存储 Axes 对象的 NumPy 数组
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))
axes 是一个二维数组,通过索引访问每个子图
axes[row, col]
左上角子图 (0, 0)
axes[0, 0].plot(x, y1, color=’red’)
axes[0, 0].set_title(“Sine Wave”)
axes[0, 0].set_xlabel(“X”)
axes[0, 0].set_ylabel(“sin(X)”)
右上角子图 (0, 1)
axes[0, 1].plot(x, y2, color=’blue’)
axes[0, 1].set_title(“Cosine Wave”)
axes[0, 1].set_xlabel(“X”)
axes[0, 1].set_ylabel(“cos(X)”)
左下角子图 (1, 0)
axes[1, 0].plot(x, y3, color=’green’)
axes[1, 0].set_title(“Linear Function”)
axes[1, 0].set_xlabel(“X”)
axes[1, 0].set_ylabel(“Y = X”)
右下角子图 (1, 1)
axes[1, 1].plot(x, y4, color=’purple’)
axes[1, 1].set_title(“Quadratic Function”)
axes[1, 1].set_xlabel(“X”)
axes[1, 1].set_ylabel(“Y = X^2”)
调整子图之间的间距,避免重叠
plt.tight_layout()
添加一个总标题 (可选,作用于整个 Figure)
fig.suptitle(“Four Different Functions”, fontsize=16, y=1.02) # y参数调整标题位置
plt.show()
“`
plt.subplots(nrows, ncols)
会创建一个 nrows
行、ncols
列的子图网格。返回的 axes
对象是一个 NumPy 数组,你可以像访问二维数组一样访问每个 Axes 对象。例如,对于一个 2×2 的网格,axes[0, 0]
是左上角的子图,axes[1, 1]
是右下角的子图。
对于只有一行或一列的子图,axes
将是一个一维数组。例如,plt.subplots(1, 2)
返回的 axes
是一个包含两个 Axes 对象的数组,可以通过 axes[0]
和 axes[1]
访问。
plt.tight_layout()
函数会自动调整子图参数,使之填充整个 Figure 区域,并尽量减少子图之间的重叠。fig.suptitle()
可以给整个 Figure 添加一个主标题。
7. 添加文本和注解
除了标题和轴标签,你可能还需要在图表的特定位置添加文本说明或指向某个数据点的注解。
“`python
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
添加文本 (在数据坐标系中指定位置)
ax.text(3, 0.5, “Peak near x=3”, fontsize=12, color=’green’)
ax.text(8, -0.8, “Valley near x=8”, fontsize=12, color=’red’, ha=’center’) # ha: horizontal alignment
添加注解和箭头
xy: 需要注解的数据点位置 (数据坐标系)
xytext: 注解文本的位置 (数据坐标系或其他坐标系)
arrowprops: 箭头属性
ax.annotate(“First minimum”, xy=(4.7, -1), xytext=(6, -1.3),
arrowprops=dict(facecolor=’black’, shrink=0.05), # shrink控制箭头离点的距离
fontsize=10)
ax.set_title(“Sine Wave with Text and Annotations”)
ax.set_xlabel(“X-axis”)
ax.set_ylabel(“Y-axis”)
ax.set_ylim(-1.2, 1.2) # 确保文本和注解可见
plt.show()
“`
ax.text(x, y, text, **kwargs)
: 在指定的x
和y
位置添加文本。默认情况下,x
和y
是数据坐标系中的值。可以通过transform
参数改变坐标系(例如,transform=ax.transAxes
使用 Axes 坐标系,范围从 0 到 1)。ax.annotate(text, xy=(x_point, y_point), xytext=(x_text, y_text), arrowprops=dict(...), **kwargs)
: 添加带有箭头的注解。xy
指定被注解点的位置,xytext
指定文本框的位置。arrowprops
是一个字典,用于定制箭头的样式。
8. 保存图表
绘制好的图表通常需要保存到文件中。使用 fig.savefig()
方法可以做到这一点。
“`python
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title(“Sine Wave to Save”)
保存图表到文件
文件格式由扩展名决定 (.png, .jpg, .pdf, .svg, etc.)
dpi: 分辨率 (dots per inch), 越大图片越清晰
bbox_inches=’tight’: 尝试去除图表周围的多余空白
fig.savefig(“sine_wave.png”, dpi=300, bbox_inches=’tight’)
fig.savefig(“sine_wave.pdf”) # 保存为PDF是矢量图,放大不失真
fig.savefig(“sine_wave.svg”) # 保存为SVG也是矢量图
print(“Plots saved successfully!”)
plt.show() # 保存后通常就不需要再显示窗口了
“`
fig.savefig()
支持多种文件格式,常用的包括 PNG(用于网页和文档)、JPG(用于照片)、PDF 和 SVG(用于矢量图,适合需要高质量输出的场景)。dpi
参数控制输出图片的分辨率,bbox_inches='tight'
参数可以自动调整边界,使图表更紧凑。
9. 其他基础定制选项
-
设置刻度 (Ticks) 和刻度标签 (Tick Labels):
“`python
fig, ax = plt.subplots()
x = [1, 2, 3, 4, 5]
y = [10, 15, 7, 12, 9]
ax.plot(x, y)设置 x 轴的刻度位置和标签
ax.set_xticks([1, 2, 3, 4, 5])
ax.set_xticklabels([‘One’, ‘Two’, ‘Three’, ‘Four’, ‘Five’])设置 y 轴刻度(自动生成位置,手动设置标签)
ax.set_yticks(np.arange(0, 20, 5)) # 从0到20,间隔5
ax.set_yticklabels([‘Low’, ‘Medium-Low’, ‘Medium’, ‘Medium-High’], rotation=45) # 旋转标签plt.show()
“` -
修改轴的样式:
“`python
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_title(“Styled Axes”)隐藏右侧和顶部的轴线
ax.spines[‘right’].set_visible(False)
ax.spines[‘top’].set_visible(False)设置底部轴线的颜色和粗细
ax.spines[‘bottom’].set_color(‘red’)
ax.spines[‘bottom’].set_linewidth(2)设置 x 轴和 y 轴刻度的颜色
ax.tick_params(axis=’x’, colors=’blue’, direction=’out’)
ax.tick_params(axis=’y’, colors=’green’, direction=’inout’)plt.show()
“` -
添加网格线:
“`python
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_title(“With Grid”)添加网格线
ax.grid(True) # 添加主网格线
可以定制网格线
ax.grid(color=’grey’, linestyle=’–‘, linewidth=0.5, which=’both’) # which=’major’, ‘minor’, or ‘both’
plt.show()
“`
10. 最佳实践和进阶方向
- 始终使用面向对象接口: 除非是非常简单的单图快速查看,否则建议总是使用
fig, ax = plt.subplots()
或fig, axes = plt.subplots()
来创建 Figure 和 Axes,并调用 Axes 对象的方法进行操作。 - 结构化你的代码: 将绘图相关的代码封装到函数中,提高代码的可读性和可重用性。
- 探索更多图表类型: Matplotlib 支持箱线图、小提琴图、错误条、3D图、等高线图等多种图表。查阅官方文档以了解更多。
- 学习使用 Pandas 的绘图功能: Pandas 的 DataFrame 和 Series 对象内置了基于 Matplotlib 的绘图方法,非常方便进行数据探索性分析。例如
df.plot(kind='bar')
。 - 了解 Seaborn 库: Seaborn 是基于 Matplotlib 的高级统计数据可视化库,提供了更美观的默认样式和更方便的统计图表绘制功能(如分布图、关系图、分类图)。它是 Matplotlib 的有力补充。
11. 总结
本教程带你入门了 Matplotlib 数据可视化,涵盖了以下基础内容:
- Matplotlib 的核心概念:Figure 和 Axes。
- 使用面向对象接口进行绘图。
- 绘制常见的图表类型:线图、散点图、柱状图、直方图、饼图。
- 定制图表的颜色、线型、标记、标题、标签、图例等元素。
- 在同一 Figure 中组织多个子图。
- 添加文本和注解。
- 保存图表到文件。
Matplotlib 是一个功能极其丰富的库,本教程只是冰山一角。但掌握了 Figure 和 Axes 的概念以及基本的绘图和定制方法,你已经具备了使用 Matplotlib 创建各种图表的基础。接下来的学习可以深入探索更多图表类型、更复杂的定制选项以及与其他库的集成。
祝你在数据可视化的旅程中越走越远!