Matplotlib 完全指南:从入门到精通
前言
Matplotlib 是 Python 中最基础、最强大的数据可视化库之一。无论你是数据分析师、数据科学家还是研究人员,掌握 Matplotlib 都是必不可少的技能。本文将带你从零开始学习 Matplotlib,帮助你掌握各种图表的绘制方法和高级技巧。
目录
- Matplotlib 简介
- 安装与基础配置
- 基础绘图
- 常用图表类型
- 图表样式与美化
- 多子图布局
- 高级技巧
- 实战案例
- 常见问题与解决方案
- 总结与资源
Matplotlib 简介
Matplotlib 是一个用于创建静态、动态和交互式图表的 Python 库。它由 John D. Hunter 在 2003 年开发,灵感来自于 MATLAB 的绘图功能。
主要特点
- 功能全面:支持多种图表类型,从简单的线图到复杂的 3D 图表
- 高度可定制:几乎所有图表元素都可以自定义
- 跨平台:支持多种输出格式(PNG、PDF、SVG 等)
- 与其他库的良好集成:特别是 NumPy 和 Pandas
- 活跃的社区:丰富的文档和示例
安装与基础配置
安装
# 使用 pip 安装
pip install matplotlib# 使用 conda 安装
conda install matplotlib
基础导入
import matplotlib.pyplot as plt
import numpy as np# 设置中文显示(解决中文乱码问题)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
Jupyter Notebook 配置
# 在 Jupyter Notebook 中显示图片
%matplotlib inline# 使用高清显示
%config InlineBackend.figure_format = 'retina'
基础绘图
第一个图表
# 创建数据
x = np.linspace(0, 10, 100)
y = np.sin(x)# 创建图表
plt.figure(figsize=(8, 6))
plt.plot(x, y)
plt.title('正弦函数图')
plt.xlabel('x 轴')
plt.ylabel('y 轴')
plt.grid(True)
plt.show()
图表的基本组成
一个完整的 Matplotlib 图表包含以下主要组件:
- Figure(画布):整个图表的容器
- Axes(坐标系):实际的绘图区域
- Axis(坐标轴):x 轴和 y 轴
- Artist(图表元素):所有可见的元素(线条、文本、标记等)
# 面向对象的绘图方式
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(x, y)
ax.set_title('正弦函数图')
ax.set_xlabel('x 轴')
ax.set_ylabel('y 轴')
ax.grid(True)
plt.show()
常用图表类型
1. 线图(Line Plot)
# 多条线图
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)plt.figure(figsize=(10, 6))
plt.plot(x, y1, label='sin(x)', color='blue', linestyle='-', linewidth=2)
plt.plot(x, y2, label='cos(x)', color='red', linestyle='--', linewidth=2)
plt.title('三角函数图')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
2. 散点图(Scatter Plot)
# 创建随机数据
np.random.seed(42)
x = np.random.randn(100)
y = 2 * x + 1 + np.random.randn(100) * 0.5plt.figure(figsize=(8, 6))
plt.scatter(x, y, c=x, cmap='viridis', alpha=0.6, s=50)
plt.colorbar(label='x值')
plt.title('散点图示例')
plt.xlabel('x')
plt.ylabel('y')
plt.show()
3. 柱状图(Bar Chart)
# 柱状图
categories = ['A', 'B', 'C', 'D', 'E']
values = [23, 45, 56, 78, 32]plt.figure(figsize=(8, 6))
bars = plt.bar(categories, values, color='skyblue', edgecolor='navy', alpha=0.7)# 在柱子上添加数值
for bar in bars:height = bar.get_height()plt.text(bar.get_x() + bar.get_width()/2., height,f'{height}', ha='center', va='bottom')plt.title('柱状图示例')
plt.xlabel('类别')
plt.ylabel('数值')
plt.grid(True, axis='y', alpha=0.3)
plt.show()
4. 直方图(Histogram)
# 生成正态分布数据
data = np.random.normal(100, 15, 1000)plt.figure(figsize=(10, 6))
n, bins, patches = plt.hist(data, bins=30, density=True, alpha=0.7, color='green', edgecolor='black')# 添加正态分布曲线
mu, sigma = np.mean(data), np.std(data)
x = np.linspace(data.min(), data.max(), 100)
plt.plot(x, 1/(sigma * np.sqrt(2 * np.pi)) * np.exp(-0.5 * ((x - mu) / sigma) ** 2),'r-', linewidth=2, label='正态分布曲线')plt.title('直方图与正态分布')
plt.xlabel('数值')
plt.ylabel('频率密度')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
5. 饼图(Pie Chart)
# 饼图数据
sizes = [30, 25, 20, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
explode = (0.05, 0, 0, 0, 0) # 突出显示第一块plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%',shadow=True, startangle=90)
plt.title('饼图示例')
plt.axis('equal')
plt.show()
6. 箱线图(Box Plot)
# 创建多组数据
data = [np.random.normal(0, std, 100) for std in range(1, 5)]plt.figure(figsize=(8, 6))
bp = plt.boxplot(data, patch_artist=True, labels=['A', 'B', 'C', 'D'])# 自定义箱线图颜色
colors = ['lightblue', 'lightgreen', 'lightpink', 'lightyellow']
for patch, color in zip(bp['boxes'], colors):patch.set_facecolor(color)plt.title('箱线图示例')
plt.xlabel('组别')
plt.ylabel('数值')
plt.grid(True, alpha=0.3)
plt.show()
图表样式与美化
1. 使用内置样式
# 查看可用样式
print(plt.style.available)# 使用样式
plt.style.use('seaborn')
# 或者使用临时样式
with plt.style.context('ggplot'):plt.plot(x, y)plt.show()
2. 自定义颜色和样式
# 自定义颜色映射
from matplotlib import cmx = np.linspace(0, 2*np.pi, 100)
fig, ax = plt.subplots(figsize=(10, 6))# 使用不同的颜色和样式
for i in range(5):y = np.sin(x + i*0.5)color = cm.viridis(i/4) # 使用颜色映射ax.plot(x, y, color=color, linewidth=2, label=f'sin(x + {i*0.5:.1f})')ax.set_title('使用颜色映射的多条曲线')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()
3. 添加注释和标记
# 创建数据
x = np.linspace(0, 10, 100)
y = np.sin(x)fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y, 'b-', linewidth=2)# 标记最大值点
max_idx = np.argmax(y)
ax.plot(x[max_idx], y[max_idx], 'ro', markersize=10)# 添加注释
ax.annotate(f'最大值: {y[max_idx]:.2f}', xy=(x[max_idx], y[max_idx]), xytext=(x[max_idx]+1, y[max_idx]+0.1),arrowprops=dict(arrowstyle='->', color='red'),fontsize=12)# 添加文本
ax.text(5, -0.5, '正弦函数', fontsize=16, ha='center',bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))ax.set_title('带注释的正弦函数图')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.grid(True, alpha=0.3)
plt.show()
多子图布局
1. 使用 subplot
# 创建 2x2 的子图
fig, axes = plt.subplots(2, 2, figsize=(12, 10))# 数据
x = np.linspace(0, 2*np.pi, 100)# 子图1:正弦函数
axes[0, 0].plot(x, np.sin(x), 'b-')
axes[0, 0].set_title('正弦函数')# 子图2:余弦函数
axes[0, 1].plot(x, np.cos(x), 'r-')
axes[0, 1].set_title('余弦函数')# 子图3:正切函数
axes[1, 0].plot(x, np.tan(x), 'g-')
axes[1, 0].set_ylim(-5, 5)
axes[1, 0].set_title('正切函数')# 子图4:组合
axes[1, 1].plot(x, np.sin(x), 'b-', label='sin(x)')
axes[1, 1].plot(x, np.cos(x), 'r-', label='cos(x)')
axes[1, 1].set_title('组合图')
axes[1, 1].legend()# 调整子图间距
plt.tight_layout()
plt.show()
2. 使用 GridSpec
from matplotlib.gridspec import GridSpecfig = plt.figure(figsize=(12, 8))
gs = GridSpec(3, 3, figure=fig)# 创建不同大小的子图
ax1 = fig.add_subplot(gs[0, :])
ax2 = fig.add_subplot(gs[1, :2])
ax3 = fig.add_subplot(gs[1:, 2])
ax4 = fig.add_subplot(gs[2, 0])
ax5 = fig.add_subplot(gs[2, 1])# 在每个子图中绘制
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title('主图')ax2.bar(['A', 'B', 'C'], [3, 7, 5])
ax2.set_title('柱状图')ax3.scatter(np.random.randn(50), np.random.randn(50))
ax3.set_title('散点图')ax4.pie([30, 70], labels=['A', 'B'])
ax4.set_title('饼图')ax5.hist(np.random.normal(0, 1, 100))
ax5.set_title('直方图')plt.tight_layout()
plt.show()
高级技巧
1. 双坐标轴
# 创建具有两个 y 轴的图表
fig, ax1 = plt.subplots(figsize=(10, 6))x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.exp(x/10)# 第一个 y 轴
color = 'tab:red'
ax1.set_xlabel('x')
ax1.set_ylabel('sin(x)', color=color)
ax1.plot(x, y1, color=color)
ax1.tick_params(axis='y', labelcolor=color)# 第二个 y 轴
ax2 = ax1.twinx()
color = 'tab:blue'
ax2.set_ylabel('exp(x/10)', color=color)
ax2.plot(x, y2, color=color)
ax2.tick_params(axis='y', labelcolor=color)plt.title('双 Y 轴图表')
fig.tight_layout()
plt.show()
2. 3D 图表
from mpl_toolkits.mplot3d import Axes3D# 创建 3D 图表
fig = plt.figure(figsize=(12, 9))
ax = fig.add_subplot(111, projection='3d')# 创建数据
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))# 绘制 3D 表面
surf = ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)# 添加轮廓线
contours = ax.contour(X, Y, Z, zdir='z', offset=-2, cmap='viridis')ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('3D 表面图')# 添加颜色条
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
3. 动画
from matplotlib.animation import FuncAnimation# 创建动画
fig, ax = plt.subplots(figsize=(8, 6))
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1.5, 1.5)x = np.linspace(0, 2*np.pi, 1000)
line, = ax.plot([], [], 'b-')def init():line.set_data([], [])return line,def animate(frame):y = np.sin(x + frame/10)line.set_data(x, y)return line,# 创建动画(这里只展示代码,实际运行需要保存或在支持的环境中显示)
anim = FuncAnimation(fig, animate, init_func=init, frames=100, interval=50, blit=True)# 保存动画
# anim.save('sine_wave.gif', writer='pillow')
plt.show()
实战案例
案例 1:股票价格分析图
# 模拟股票数据
dates = pd.date_range('2023-01-01', periods=100)
stock_price = 100 + np.cumsum(np.random.randn(100) * 2)
volume = np.random.randint(1000000, 5000000, 100)fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True)# 价格图
ax1.plot(dates, stock_price, 'b-', linewidth=2)
ax1.fill_between(dates, stock_price, alpha=0.3)
ax1.set_ylabel('价格 (元)')
ax1.set_title('股票价格走势图')
ax1.grid(True, alpha=0.3)# 成交量图
ax2.bar(dates, volume, color='gray', alpha=0.7)
ax2.set_ylabel('成交量')
ax2.set_xlabel('日期')
ax2.grid(True, alpha=0.3)plt.tight_layout()
plt.show()
案例 2:数据分析仪表盘
# 创建仪表盘布局
fig = plt.figure(figsize=(15, 10))
gs = GridSpec(3, 3, figure=fig, hspace=0.3, wspace=0.3)# 数据准备
np.random.seed(42)
categories = ['产品A', '产品B', '产品C', '产品D', '产品E']
sales = np.random.randint(50, 200, 5)
months = ['1月', '2月', '3月', '4月', '5月', '6月']
monthly_sales = np.random.randint(100, 500, (6, 5))# 1. 总销售额饼图
ax1 = fig.add_subplot(gs[0, :2])
ax1.pie(sales, labels=categories, autopct='%1.1f%%', startangle=90)
ax1.set_title('产品销售占比')# 2. 月度销售趋势
ax2 = fig.add_subplot(gs[0, 2])
for i, product in enumerate(categories):ax2.plot(months, monthly_sales[:, i], marker='o', label=product)ax2.set_title('月度销售趋势')ax2.legend(fontsize=8)ax2.grid(True, alpha=0.3)# 3. 销售额柱状图ax3 = fig.add_subplot(gs[1, :])x = np.arange(len(categories))width = 0.15for i, month in enumerate(months[:4]):ax3.bar(x + i*width, monthly_sales[i], width, label=month)ax3.set_xlabel('产品')ax3.set_ylabel('销售额')ax3.set_title('各产品月度销售对比')ax3.set_xticks(x + width * 1.5)ax3.set_xticklabels(categories)ax3.legend()ax3.grid(True, axis='y', alpha=0.3)# 4. 销售额热力图ax4 = fig.add_subplot(gs[2, :2])im = ax4.imshow(monthly_sales, cmap='YlOrRd', aspect='auto')ax4.set_xticks(np.arange(len(categories)))ax4.set_yticks(np.arange(len(months)))ax4.set_xticklabels(categories)ax4.set_yticklabels(months)ax4.set_title('销售额热力图')# 在热力图上显示数值for i in range(len(months)):for j in range(len(categories)):text = ax4.text(j, i, monthly_sales[i, j],ha="center", va="center", color="black")# 5. KPI 指标ax5 = fig.add_subplot(gs[2, 2])ax5.text(0.5, 0.7, '总销售额', ha='center', va='center', fontsize=14)ax5.text(0.5, 0.5, f'{np.sum(monthly_sales):,}', ha='center', va='center', fontsize=24, fontweight='bold', color='red')ax5.text(0.5, 0.3, '同比增长 +23.5%', ha='center', va='center', fontsize=12, color='green')ax5.set_xlim(0, 1)ax5.set_ylim(0, 1)ax5.axis('off')plt.suptitle('销售数据分析仪表盘', fontsize=16)plt.show()
常见问题与解决方案
1. 中文显示问题
# 解决方案1:设置字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS
plt.rcParams['axes.unicode_minus'] = False# 解决方案2:使用 FontProperties
from matplotlib.font_manager import FontProperties
font = FontProperties(fname='path/to/font.ttf')
plt.title('中文标题', fontproperties=font)
2. 图表大小和分辨率
# 设置图表大小
plt.figure(figsize=(12, 8))# 设置 DPI(分辨率)
plt.figure(dpi=150)# 保存高分辨率图片
plt.savefig('figure.png', dpi=300, bbox_inches='tight')
3. 图例位置调整
# 自动调整位置
plt.legend(loc='best')# 指定位置
plt.legend(loc='upper right')# 放在图表外部
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
4. 坐标轴范围和刻度
# 设置坐标轴范围
plt.xlim(0, 10)
plt.ylim(-1, 1)# 设置刻度
plt.xticks(np.arange(0, 11, 2))
plt.yticks([-1, -0.5, 0, 0.5, 1])# 旋转刻度标签
plt.xticks(rotation=45)
总结与资源
学习要点回顾
- 基础概念:理解 Figure、Axes、Axis 等核心概念
- 绘图方式:掌握函数式和面向对象两种绘图方式
- 图表类型:熟练使用各种常见图表类型
- 样式美化:学会自定义图表样式和颜色
- 布局技巧:掌握多子图和复杂布局
- 高级功能:了解 3D 绘图、动画等高级特性
推荐资源
- 官方文档:matplotlib.org
- 示例库:Matplotlib Gallery
- 教程:
- Matplotlib Tutorial
- Python Data Science Handbook
- 相关库:
- Seaborn:基于 Matplotlib 的统计图表库
- Plotly:交互式图表库
- Bokeh:Web 交互式可视化
最佳实践
- 选择合适的图表类型:根据数据特点和展示目的选择
- 保持简洁:避免过度装饰,突出数据本身
- 使用有意义的标签:确保轴标签、标题清晰明了
- 选择合适的颜色:考虑色盲用户,使用对比度高的配色
- 添加必要的说明:使用图例、注释等帮助理解
结语
Matplotlib 是 Python 数据可视化的基石,掌握它将为你的数据分析工作提供强大支持。通过本文的学习,相信你已经对 Matplotlib 有了全面的了解。记住,最好的学习方式是实践,多动手尝试不同的图表和参数,逐步提升你的可视化技能。
Happy plotting! 🎨📊