Matplotlib 课程

一、什么是 Matplotlib?

Matplotlib 是 Python 最著名、使用最广泛的二维绘图库,可以创建高质量的静态、动态和交互式可视化图表。

核心特点

  • 跨平台:支持 Windows、Linux、macOS
  • 多后端:支持 PNG、PDF、SVG 等多种输出格式
  • 语法类似 MATLAB:MATLAB 用户容易上手
  • 高度可定制:几乎可以控制图形的每个元素
  • 丰富图表类型:线图、散点图、柱状图、3D图等

二、安装与导入

安装

pip install matplotlib

导入约定

import matplotlib.pyplot as plt  # 主要接口
import numpy as np  # 通常与NumPy一起使用

三、基本架构(重要概念)

1. 三层结构

Figure(画布)
    ↑
Axes(坐标系/子图)← 主要的绘图区域
    ↑
Axis(坐标轴)

2. 核心对象关系

import matplotlib.pyplot as plt

# 创建图形和坐标轴
fig, ax = plt.subplots()  # 推荐方式(面向对象)
# 等价于:
# fig = plt.figure()       # 创建画布
# ax = fig.add_subplot()   # 添加坐标轴

ax.plot([1, 2, 3, 4], [1, 4, 2, 3])  # 在坐标轴上绘图
plt.show()  # 显示图形

四、两种编程风格

1. MATLAB 风格(简单快速)

import matplotlib.pyplot as plt

# 直接使用 pyplot 函数
plt.figure(figsize=(8, 6))           # 创建图形
plt.plot([1, 2, 3, 4], [1, 4, 2, 3]) # 绘图
plt.title('简单线图')                 # 添加标题
plt.xlabel('X轴')                     # X轴标签
plt.ylabel('Y轴')                     # Y轴标签
plt.grid(True)                        # 显示网格
plt.show()                            # 显示图形

2. 面向对象风格(推荐,更清晰)

fig, ax = plt.subplots(figsize=(8, 6))  # 创建图形和坐标轴
ax.plot([1, 2, 3, 4], [1, 4, 2, 3])     # 在坐标轴上绘图
ax.set_title('简单线图')                  # 设置标题
ax.set_xlabel('X轴')                     # 设置X轴标签
ax.set_ylabel('Y轴')                     # 设置Y轴标签
ax.grid(True)                            # 显示网格
fig.savefig('plot.png', dpi=300)         # 保存图形
plt.show()                               # 显示图形

五、基本图表类型

1. 线图(Line Plot)

x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y, 
        color='blue',        # 颜色
        linewidth=2,         # 线宽
        linestyle='--',      # 线型
        marker='o',          # 标记点
        markersize=8,        # 标记大小
        label='sin(x)')      # 图例标签
ax.legend()                  # 显示图例
plt.show()

2. 散点图(Scatter Plot)

np.random.seed(42)
x = np.random.randn(100)
y = np.random.randn(100)
colors = np.random.rand(100)
sizes = 1000 * np.random.rand(100)

fig, ax = plt.subplots(figsize=(10, 6))
scatter = ax.scatter(x, y, 
                     c=colors,      # 颜色数组
                     s=sizes,       # 大小数组
                     alpha=0.5,     # 透明度
                     cmap='viridis')# 颜色映射
ax.set_title('气泡图示例')
fig.colorbar(scatter)  # 添加颜色条
plt.show()

3. 柱状图(Bar Chart)

categories = ['A', 'B', 'C', 'D', 'E']
values = [23, 45, 56, 78, 33]
errors = [2, 3, 4, 1, 2]

fig, ax = plt.subplots(figsize=(10, 6))
bars = ax.bar(categories, values, 
              yerr=errors,      # 误差线
              color=['red', 'blue', 'green', 'orange', 'purple'],
              edgecolor='black',
              capsize=5)        # 误差线帽子大小

# 添加数值标签
for bar in bars:
    height = bar.get_height()
    ax.text(bar.get_x() + bar.get_width()/2., height,
            f'{height}', ha='center', va='bottom')

ax.set_ylabel('数值')
ax.set_title('柱状图示例')
plt.show()

4. 直方图(Histogram)

data = np.random.randn(1000)

fig, ax = plt.subplots(figsize=(10, 6))
n, bins, patches = ax.hist(data, 
                           bins=30,        # 箱数
                           density=True,   # 归一化
                           alpha=0.7,      # 透明度
                           color='steelblue',
                           edgecolor='black')

# 添加拟合曲线
from scipy.stats import norm
x = np.linspace(-4, 4, 100)
ax.plot(x, norm.pdf(x), 'r-', linewidth=2)

ax.set_title('正态分布直方图')
ax.set_xlabel('数值')
ax.set_ylabel('频率')
plt.show()

5. 饼图(Pie Chart)

labels = ['Python', 'Java', 'C++', 'JavaScript', 'Go']
sizes = [40, 25, 15, 10, 10]
explode = (0.1, 0, 0, 0, 0)  # 突出第一块

fig, ax = plt.subplots(figsize=(8, 8))
wedges, texts, autotexts = ax.pie(sizes, 
                                   explode=explode,
                                   labels=labels,
                                   autopct='%1.1f%%',
                                   shadow=True,
                                   startangle=90)

# 美化文本
for autotext in autotexts:
    autotext.set_color('white')
    autotext.set_fontsize(12)

ax.set_title('编程语言市场份额')
plt.show()

六、多子图布局

1. subplot 网格布局

fig, axes = plt.subplots(2, 3, figsize=(15, 10))  # 2行3列
fig.suptitle('多子图示例', fontsize=16)

# 遍历所有坐标轴
for i, ax in enumerate(axes.flat):
    x = np.linspace(0, 2*np.pi, 100)
    y = np.sin(x + i*0.5)
    ax.plot(x, y)
    ax.set_title(f'子图 {i+1}')
    ax.grid(True)

plt.tight_layout()  # 自动调整子图间距
plt.show()

2. 复杂布局 GridSpec

fig = plt.figure(figsize=(12, 8))
gs = fig.add_gridspec(3, 3)  # 3行3列网格

# 创建不同大小的子图
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])        # 第三行,第二列

# 在各个子图中绘图
axes = [ax1, ax2, ax3, ax4, ax5]
for i, ax in enumerate(axes):
    ax.plot(np.random.rand(10))
    ax.set_title(f'Axes {i+1}')

plt.tight_layout()
plt.show()

七、样式与美化

1. 使用内置样式

print(plt.style.available)  # 查看所有可用样式

plt.style.use('seaborn-v0_8-darkgrid')  # 应用样式

fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 10, 100)
for i in range(5):
    ax.plot(x, np.sin(x + i*0.5), label=f'曲线 {i+1}')
ax.legend()
plt.show()

2. 自定义样式

# 自定义rc参数
plt.rcParams.update({
    'figure.figsize': (10, 6),        # 图形大小
    'font.size': 12,                   # 字体大小
    'axes.titlesize': 16,              # 标题大小
    'axes.labelsize': 14,              # 轴标签大小
    'xtick.labelsize': 12,             # X轴刻度标签大小
    'ytick.labelsize': 12,             # Y轴刻度标签大小
    'legend.fontsize': 12,             # 图例字体大小
    'lines.linewidth': 2,              # 线宽
    'lines.markersize': 8,             # 标记大小
})

fig, ax = plt.subplots()
# 绘图...
plt.show()

3. 颜色和线型

# 内置颜色缩写
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']
# 对应:蓝、绿、红、青、品红、黄、黑、白

# 线型
linestyles = ['-', '--', '-.', ':', 'None']

# 标记点
markers = ['.', ',', 'o', 'v', '^', '<', '>', 
           '1', '2', '3', '4', 's', 'p', '*', 
           'h', 'H', '+', 'x', 'D', 'd', '|', '_']

fig, ax = plt.subplots(figsize=(12, 6))
x = np.arange(10)

# 演示不同样式
for i in range(10):
    ax.plot(x, x + i, 
            color=f'C{i}',          # 使用调色板颜色
            linestyle=linestyles[i % len(linestyles)],
            marker=markers[i % len(markers)],
            label=f'Line {i+1}')

ax.legend(ncol=2)
plt.show()

八、3D 绘图

from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# 生成数据
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
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',      # 颜色映射
                       edgecolor='none',    # 边线颜色
                       alpha=0.8)           # 透明度

# 绘制等高线
ax.contour(X, Y, Z, zdir='z', offset=-1.5, 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()

九、动画功能

from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots(figsize=(8, 6))
x = np.linspace(0, 4*np.pi, 200)
line, = ax.plot(x, np.sin(x))

def update(frame):
    line.set_ydata(np.sin(x + frame/10))  # 更新数据
    return line,

ani = FuncAnimation(fig, update, frames=100, 
                    interval=50, blit=True)
plt.show()

# 保存动画
# ani.save('animation.gif', writer='pillow', fps=30)

十、实战案例

1. 股票数据可视化

# 模拟股票数据
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=100, freq='D')
prices = 100 + np.cumsum(np.random.randn(100))

fig, axes = plt.subplots(2, 1, figsize=(12, 10))

# 价格走势图
axes[0].plot(dates, prices, 'b-', linewidth=2)
axes[0].fill_between(dates, prices.min(), prices, alpha=0.3)
axes[0].set_title('股票价格走势')
axes[0].set_ylabel('价格')
axes[0].grid(True)

# 收益率直方图
returns = np.diff(prices) / prices[:-1]
axes[1].hist(returns, bins=30, density=True, alpha=0.7)
axes[1].axvline(x=returns.mean(), color='red', linestyle='--', label='均值')
axes[1].set_title('收益率分布')
axes[1].set_xlabel('收益率')
axes[1].set_ylabel('频率')
axes[1].legend()

plt.tight_layout()
plt.show()

2. 机器学习结果可视化

from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression

# 生成数据
X, y = make_classification(n_samples=100, n_features=2, 
                           n_redundant=0, random_state=42)

# 训练模型
model = LogisticRegression()
model.fit(X, y)

fig, ax = plt.subplots(figsize=(10, 8))

# 绘制决策边界
h = 0.02
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

# 绘制背景
ax.contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')

# 绘制数据点
scatter = ax.scatter(X[:, 0], X[:, 1], c=y, 
                     cmap='coolwarm', edgecolor='k', s=100)

# 设置图形属性
ax.set_xlabel('特征1')
ax.set_ylabel('特征2')
ax.set_title('逻辑回归决策边界')
plt.colorbar(scatter)
plt.show()

实用技巧

1. 保存图形

fig.savefig('figure.png', 
            dpi=300,            # 分辨率
            bbox_inches='tight', # 紧凑布局
            facecolor='white',   # 背景色
            edgecolor='none')    # 边框

2. 显示中文字体

import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体
matplotlib.rcParams['axes.unicode_minus'] = False    # 解决负号显示问题

3. 常用配置

# 创建图形时一次性设置
fig, ax = plt.subplots(figsize=(10, 6), 
                       dpi=100, 
                       facecolor='white',
                       edgecolor='gray')

# 设置坐标轴范围
ax.set_xlim(0, 10)
ax.set_ylim(-2, 2)

# 设置坐标轴刻度
ax.set_xticks([0, 2, 4, 6, 8, 10])
ax.set_yticks([-2, -1, 0, 1, 2])

# 设置刻度标签
ax.set_xticklabels(['零', '二', '四', '六', '八', '十'])

# 添加文本
ax.text(5, 1.5, '重要数据点', 
        fontsize=12, 
        ha='center', 
        va='center',
        bbox=dict(boxstyle='round', facecolor='yellow', alpha=0.5))

学习建议

  1. 从面向对象风格开始:虽然代码稍长,但更清晰、灵活
  2. 多实践:尝试修改各种参数,观察效果
  3. 参考官方示例:Matplotlib官网有大量示例和教程
  4. 结合使用:与Pandas、Seaborn等库配合使用

Matplotlib是Python数据可视化的基石,虽然Seaborn、Plotly等库提供了更高级的接口,但掌握Matplotlib能让你更好地控制图形细节,理解可视化的底层原理。