行莫
行莫
发布于 2025-11-20 / 7 阅读
0
0

Matplotlib 数据可视化详解

Matplotlib 数据可视化详解

目录

  1. Matplotlib 简介
  2. 安装与环境准备
  3. 基础绘图
  4. 常用图表类型
  5. 子图和布局
  6. 样式和美化
  7. 3D 绘图
  8. 动画
  9. 保存图片
  10. 实战案例
  11. 最佳实践

Matplotlib 简介

Matplotlib 是 Python 中最流行的数据可视化库之一,它提供了类似 MATLAB 的绘图接口,可以创建各种静态、动态和交互式图表。

主要特点

  • 功能强大:支持线图、柱状图、散点图、饼图、3D 图等多种图表类型
  • 高度可定制:可以自定义图表的每个细节
  • 兼容性好:与 NumPy、Pandas 等库完美集成
  • 跨平台:支持 Windows、Linux、macOS

Matplotlib 架构

  • Figure( figure):整个图形窗口
  • Axes(坐标轴):实际的绘图区域
  • Axis(轴):坐标轴(x 轴、y 轴)
  • Artist(艺术家):所有可见元素的基类

安装与环境准备

安装 Matplotlib

pip install matplotlib

导入和基本设置

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings('ignore')

# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 设置图表样式
plt.style.use('default')  # 可选: 'seaborn', 'ggplot', 'dark_background' 等

print(f"Matplotlib 版本: {plt.matplotlib.__version__}")
print(f"NumPy 版本: {np.__version__}")

创建测试数据

# 生成测试数据
np.random.seed(42)

# 线性数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

# 随机数据
x_random = np.random.randn(100)
y_random = np.random.randn(100)

# 分类数据
categories = ['A', 'B', 'C', 'D', 'E']
values = [23, 45, 56, 78, 32]

# 时间序列数据
dates = pd.date_range('2024-01-01', periods=30, freq='D')
time_series = np.cumsum(np.random.randn(30)) + 100

print("测试数据准备完成!")

基础绘图

1. 最简单的绘图

# 示例 1:最简单的线图
plt.figure(figsize=(8, 6))
plt.plot(x, y1)
plt.title('简单的正弦函数图')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.grid(True)
plt.show()

2. 多条线图

# 示例 2:绘制多条线
plt.figure(figsize=(10, 6))
plt.plot(x, y1, label='sin(x)', linewidth=2)
plt.plot(x, y2, label='cos(x)', linewidth=2)
plt.title('三角函数对比图')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.legend()  # 显示图例
plt.grid(True, alpha=0.3)
plt.show()

3. 设置线条样式

# 示例 3:不同的线条样式
plt.figure(figsize=(12, 6))

# 实线
plt.plot(x, y1, '-', label='实线', linewidth=2)

# 虚线
plt.plot(x, y1 + 0.5, '--', label='虚线', linewidth=2)

# 点线
plt.plot(x, y1 + 1.0, '-.', label='点线', linewidth=2)

# 点
plt.plot(x, y1 + 1.5, ':', label='点线', linewidth=2)

plt.title('不同线条样式')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

4. 设置颜色和标记

# 示例 4:颜色和标记
plt.figure(figsize=(12, 6))

# 使用颜色名称
plt.plot(x[:20], y1[:20], 'o-', color='red', label='红色圆点', markersize=8)

# 使用十六进制颜色
plt.plot(x[:20], y2[:20], 's-', color='#3498db', label='蓝色方块', markersize=8)

# 使用 RGB 颜色
plt.plot(x[:20], (y1 + y2)[:20], '^-', color=(0.2, 0.8, 0.2), label='绿色三角', markersize=8)

plt.title('不同颜色和标记样式')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

5. 设置坐标轴范围和刻度

# 示例 5:自定义坐标轴
plt.figure(figsize=(10, 6))
plt.plot(x, y1)

# 设置坐标轴范围
plt.xlim(0, 10)
plt.ylim(-1.5, 1.5)

# 设置刻度
plt.xticks(np.arange(0, 11, 2))
plt.yticks(np.arange(-1.5, 2, 0.5))

# 设置坐标轴标签
plt.xlabel('X 轴标签', fontsize=12)
plt.ylabel('Y 轴标签', fontsize=12)

plt.title('自定义坐标轴')
plt.grid(True, alpha=0.3)
plt.show()

常用图表类型

1. 散点图(Scatter Plot)

# 示例 6:散点图
plt.figure(figsize=(10, 6))

# 基本散点图
plt.scatter(x_random, y_random, alpha=0.6, s=50)

plt.title('散点图')
plt.xlabel('X 值')
plt.ylabel('Y 值')
plt.grid(True, alpha=0.3)
plt.show()

# 示例 7:带颜色和大小的散点图
plt.figure(figsize=(10, 6))

# 根据第三个变量设置颜色和大小
colors = np.random.rand(100)
sizes = 1000 * np.random.rand(100)

plt.scatter(x_random, y_random, c=colors, s=sizes, alpha=0.6, cmap='viridis')
plt.colorbar(label='颜色值')

plt.title('彩色散点图(带大小变化)')
plt.xlabel('X 值')
plt.ylabel('Y 值')
plt.grid(True, alpha=0.3)
plt.show()

2. 柱状图(Bar Chart)

# 示例 8:垂直柱状图
plt.figure(figsize=(10, 6))
plt.bar(categories, values, color=['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6'])
plt.title('垂直柱状图')
plt.xlabel('类别')
plt.ylabel('数值')
plt.grid(True, alpha=0.3, axis='y')
plt.show()

# 示例 9:水平柱状图
plt.figure(figsize=(10, 6))
plt.barh(categories, values, color=['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6'])
plt.title('水平柱状图')
plt.xlabel('数值')
plt.ylabel('类别')
plt.grid(True, alpha=0.3, axis='x')
plt.show()

# 示例 10:分组柱状图
categories_group = ['类别A', '类别B', '类别C']
values1 = [20, 35, 30]
values2 = [25, 32, 34]
values3 = [30, 20, 25]

x_pos = np.arange(len(categories_group))
width = 0.25

plt.figure(figsize=(10, 6))
plt.bar(x_pos - width, values1, width, label='组1', color='#3498db')
plt.bar(x_pos, values2, width, label='组2', color='#e74c3c')
plt.bar(x_pos + width, values3, width, label='组3', color='#2ecc71')

plt.xlabel('类别')
plt.ylabel('数值')
plt.title('分组柱状图')
plt.xticks(x_pos, categories_group)
plt.legend()
plt.grid(True, alpha=0.3, axis='y')
plt.show()

# 示例 11:堆叠柱状图
plt.figure(figsize=(10, 6))
plt.bar(categories_group, values1, label='组1', color='#3498db')
plt.bar(categories_group, values2, bottom=values1, label='组2', color='#e74c3c')
plt.bar(categories_group, values3, bottom=np.array(values1) + np.array(values2), 
        label='组3', color='#2ecc71')

plt.xlabel('类别')
plt.ylabel('数值')
plt.title('堆叠柱状图')
plt.legend()
plt.grid(True, alpha=0.3, axis='y')
plt.show()

3. 直方图(Histogram)

# 示例 12:直方图
data_normal = np.random.normal(100, 15, 1000)

plt.figure(figsize=(10, 6))
plt.hist(data_normal, bins=30, color='#3498db', edgecolor='black', alpha=0.7)
plt.title('正态分布直方图')
plt.xlabel('数值')
plt.ylabel('频数')
plt.grid(True, alpha=0.3, axis='y')
plt.show()

# 示例 13:多个分布的直方图
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(3, 1.5, 1000)

plt.figure(figsize=(10, 6))
plt.hist(data1, bins=30, alpha=0.5, label='分布1', color='#3498db')
plt.hist(data2, bins=30, alpha=0.5, label='分布2', color='#e74c3c')
plt.title('多个分布对比')
plt.xlabel('数值')
plt.ylabel('频数')
plt.legend()
plt.grid(True, alpha=0.3, axis='y')
plt.show()

4. 饼图(Pie Chart)

# 示例 14:基本饼图
plt.figure(figsize=(8, 8))
colors_pie = ['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6']
explode = (0.1, 0, 0, 0, 0)  # 突出显示第一块

plt.pie(values, labels=categories, colors=colors_pie, explode=explode,
        autopct='%1.1f%%', shadow=True, startangle=90)
plt.title('饼图示例')
plt.show()

# 示例 15:环形图
plt.figure(figsize=(8, 8))
plt.pie(values, labels=categories, colors=colors_pie, autopct='%1.1f%%',
        startangle=90, pctdistance=0.85)
# 绘制内圆
centre_circle = plt.Circle((0, 0), 0.70, fc='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)
plt.title('环形图')
plt.show()

5. 箱线图(Box Plot)

# 示例 16:箱线图
data_box = [np.random.normal(0, std, 100) for std in range(1, 5)]

plt.figure(figsize=(10, 6))
plt.boxplot(data_box, labels=['组1', '组2', '组3', '组4'])
plt.title('箱线图')
plt.ylabel('数值')
plt.grid(True, alpha=0.3, axis='y')
plt.show()

# 示例 17:水平箱线图
plt.figure(figsize=(10, 6))
plt.boxplot(data_box, labels=['组1', '组2', '组3', '组4'], vert=False)
plt.title('水平箱线图')
plt.xlabel('数值')
plt.grid(True, alpha=0.3, axis='x')
plt.show()

6. 面积图(Area Plot)

# 示例 18:面积图
x_area = np.linspace(0, 10, 100)
y_area1 = np.sin(x_area)
y_area2 = np.cos(x_area)

plt.figure(figsize=(10, 6))
plt.fill_between(x_area, y_area1, alpha=0.5, label='sin(x)', color='#3498db')
plt.fill_between(x_area, y_area2, alpha=0.5, label='cos(x)', color='#e74c3c')
plt.plot(x_area, y_area1, color='#2980b9', linewidth=2)
plt.plot(x_area, y_area2, color='#c0392b', linewidth=2)
plt.title('面积图')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

7. 热力图(Heatmap)

# 示例 19:热力图
data_heatmap = np.random.rand(10, 10)

plt.figure(figsize=(10, 8))
plt.imshow(data_heatmap, cmap='viridis', aspect='auto')
plt.colorbar(label='数值')
plt.title('热力图')
plt.show()

# 使用 seaborn 风格的热力图(如果安装了 seaborn)
try:
    import seaborn as sns
    plt.figure(figsize=(10, 8))
    sns.heatmap(data_heatmap, annot=True, fmt='.2f', cmap='coolwarm')
    plt.title('带标注的热力图')
    plt.show()
except ImportError:
    print("seaborn 未安装,跳过此示例")

8. 等高线图(Contour Plot)

# 示例 20:等高线图
x_contour = np.linspace(-3, 3, 100)
y_contour = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x_contour, y_contour)
Z = np.exp(-(X**2 + Y**2))

plt.figure(figsize=(10, 8))
contour = plt.contour(X, Y, Z, levels=10)
plt.clabel(contour, inline=True, fontsize=8)
plt.colorbar(contour, label='Z 值')
plt.title('等高线图')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.show()

# 填充等高线图
plt.figure(figsize=(10, 8))
contourf = plt.contourf(X, Y, Z, levels=20, cmap='viridis')
plt.colorbar(contourf, label='Z 值')
plt.title('填充等高线图')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.show()

子图和布局

1. 使用 subplot 创建子图

# 示例 21:使用 subplot 创建子图
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 子图 1:线图
axes[0, 0].plot(x, y1, color='#3498db')
axes[0, 0].set_title('正弦函数')
axes[0, 0].grid(True, alpha=0.3)

# 子图 2:散点图
axes[0, 1].scatter(x_random[:50], y_random[:50], alpha=0.6, color='#e74c3c')
axes[0, 1].set_title('散点图')
axes[0, 1].grid(True, alpha=0.3)

# 子图 3:柱状图
axes[1, 0].bar(categories, values, color='#2ecc71')
axes[1, 0].set_title('柱状图')
axes[1, 0].grid(True, alpha=0.3, axis='y')

# 子图 4:直方图
axes[1, 1].hist(data_normal, bins=30, color='#f39c12', alpha=0.7, edgecolor='black')
axes[1, 1].set_title('直方图')
axes[1, 1].grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()

2. 使用 subplot2grid 创建复杂布局

# 示例 22:使用 subplot2grid 创建复杂布局
fig = plt.figure(figsize=(14, 10))

# 创建不同大小的子图
ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=2)
ax2 = plt.subplot2grid((3, 3), (0, 2))
ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=3)
ax4 = plt.subplot2grid((3, 3), (2, 0), colspan=2)
ax5 = plt.subplot2grid((3, 3), (2, 2))

# 填充各个子图
ax1.plot(x, y1, color='#3498db')
ax1.set_title('子图 1')
ax1.grid(True, alpha=0.3)

ax2.bar(categories[:3], values[:3], color='#e74c3c')
ax2.set_title('子图 2')

ax3.plot(x, y2, color='#2ecc71')
ax3.set_title('子图 3')
ax3.grid(True, alpha=0.3)

ax4.scatter(x_random[:50], y_random[:50], alpha=0.6, color='#f39c12')
ax4.set_title('子图 4')
ax4.grid(True, alpha=0.3)

ax5.pie(values[:3], labels=categories[:3], autopct='%1.1f%%')
ax5.set_title('子图 5')

plt.tight_layout()
plt.show()

3. 使用 GridSpec 创建网格布局

# 示例 23:使用 GridSpec 创建网格布局
from matplotlib.gridspec import GridSpec

fig = plt.figure(figsize=(14, 10))
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])

# 填充子图
ax1.plot(x, y1, color='#3498db')
ax1.set_title('顶部全宽子图')
ax1.grid(True, alpha=0.3)

ax2.bar(categories, values, color='#e74c3c')
ax2.set_title('左侧子图')

ax3.hist(data_normal, bins=20, color='#2ecc71', orientation='horizontal')
ax3.set_title('右侧子图')

ax4.scatter(x_random[:30], y_random[:30], alpha=0.6, color='#f39c12')
ax4.set_title('左下子图')

ax5.pie(values[:3], labels=categories[:3], autopct='%1.1f%%')
ax5.set_title('右下子图')

plt.tight_layout()
plt.show()

样式和美化

1. 使用样式表

# 示例 24:使用不同的样式表
styles = ['default', 'seaborn-v0_8', 'ggplot', 'dark_background']

for style in styles:
    try:
        plt.style.use(style)
        fig, ax = plt.subplots(figsize=(8, 6))
        ax.plot(x, y1, label='sin(x)')
        ax.plot(x, y2, label='cos(x)')
        ax.set_title(f'样式: {style}')
        ax.legend()
        ax.grid(True, alpha=0.3)
        plt.show()
    except:
        print(f"样式 {style} 不可用")

2. 自定义样式

# 示例 25:自定义样式
plt.rcParams.update({
    'figure.figsize': (10, 6),
    'font.size': 12,
    'axes.labelsize': 14,
    'axes.titlesize': 16,
    'xtick.labelsize': 10,
    'ytick.labelsize': 10,
    'legend.fontsize': 12,
    'axes.grid': True,
    'grid.alpha': 0.3,
    'axes.spines.left': True,
    'axes.spines.bottom': True,
    'axes.spines.top': False,
    'axes.spines.right': False
})

plt.figure()
plt.plot(x, y1, label='sin(x)', linewidth=2)
plt.plot(x, y2, label='cos(x)', linewidth=2)
plt.title('自定义样式示例')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.legend()
plt.show()

3. 添加文本和注释

# 示例 26:添加文本和注释
plt.figure(figsize=(10, 6))
plt.plot(x, y1, label='sin(x)', linewidth=2)

# 添加文本
plt.text(5, 0.5, '这是文本', fontsize=12, color='red')

# 添加箭头注释
plt.annotate('最大值', xy=(np.pi/2, 1), xytext=(4, 0.5),
            arrowprops=dict(arrowstyle='->', color='red', lw=2),
            fontsize=12, color='red')

# 添加矩形
from matplotlib.patches import Rectangle
rect = Rectangle((2, -0.5), 2, 1, linewidth=2, edgecolor='blue', 
                facecolor='yellow', alpha=0.3)
plt.gca().add_patch(rect)

plt.title('添加文本和注释')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.grid(True, alpha=0.3)
plt.show()

4. 设置图例

# 示例 27:自定义图例
plt.figure(figsize=(10, 6))
line1, = plt.plot(x, y1, label='sin(x)', linewidth=2, color='#3498db')
line2, = plt.plot(x, y2, label='cos(x)', linewidth=2, color='#e74c3c')

# 自定义图例位置和样式
plt.legend(loc='upper right', frameon=True, fancybox=True, shadow=True,
          fontsize=12, title='函数', title_fontsize=14)

plt.title('自定义图例')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.grid(True, alpha=0.3)
plt.show()

5. 双 Y 轴

# 示例 28:双 Y 轴
fig, ax1 = plt.subplots(figsize=(10, 6))

# 左 Y 轴
color = 'tab:blue'
ax1.set_xlabel('X 轴')
ax1.set_ylabel('sin(x)', color=color)
line1 = ax1.plot(x, y1, color=color, linewidth=2, label='sin(x)')
ax1.tick_params(axis='y', labelcolor=color)
ax1.grid(True, alpha=0.3)

# 右 Y 轴
ax2 = ax1.twinx()
color = 'tab:red'
ax2.set_ylabel('cos(x)', color=color)
line2 = ax2.plot(x, y2, color=color, linewidth=2, label='cos(x)')
ax2.tick_params(axis='y', labelcolor=color)

# 合并图例
lines = line1 + line2
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper right')

plt.title('双 Y 轴图表')
plt.tight_layout()
plt.show()

3D 绘图

1. 3D 线图

# 示例 29:3D 线图
from mpl_toolkits.mplot3d import Axes3D

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

# 创建 3D 螺旋线
t = np.linspace(0, 20, 100)
x_3d = np.sin(t)
y_3d = np.cos(t)
z_3d = t

ax.plot(x_3d, y_3d, z_3d, linewidth=2)
ax.set_xlabel('X 轴')
ax.set_ylabel('Y 轴')
ax.set_zlabel('Z 轴')
ax.set_title('3D 线图')
plt.show()

2. 3D 散点图

# 示例 30:3D 散点图
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# 生成 3D 随机数据
x_3d_scatter = np.random.randn(100)
y_3d_scatter = np.random.randn(100)
z_3d_scatter = np.random.randn(100)
colors_3d = np.random.rand(100)
sizes_3d = 100 * np.random.rand(100)

ax.scatter(x_3d_scatter, y_3d_scatter, z_3d_scatter, 
          c=colors_3d, s=sizes_3d, alpha=0.6, cmap='viridis')
ax.set_xlabel('X 轴')
ax.set_ylabel('Y 轴')
ax.set_zlabel('Z 轴')
ax.set_title('3D 散点图')
plt.show()

3. 3D 曲面图

# 示例 31:3D 曲面图
fig = plt.figure(figsize=(12, 10))
ax = fig.add_subplot(111, projection='3d')

# 创建网格
x_surf = np.linspace(-5, 5, 50)
y_surf = np.linspace(-5, 5, 50)
X_surf, Y_surf = np.meshgrid(x_surf, y_surf)
Z_surf = np.sin(np.sqrt(X_surf**2 + Y_surf**2))

# 绘制曲面
surf = ax.plot_surface(X_surf, Y_surf, Z_surf, cmap='viridis', alpha=0.9)
fig.colorbar(surf, ax=ax, shrink=0.5)

ax.set_xlabel('X 轴')
ax.set_ylabel('Y 轴')
ax.set_zlabel('Z 轴')
ax.set_title('3D 曲面图')
plt.show()

4. 3D 等高线图

# 示例 32:3D 等高线图
fig = plt.figure(figsize=(12, 10))
ax = fig.add_subplot(111, projection='3d')

# 创建数据
x_contour_3d = np.linspace(-3, 3, 50)
y_contour_3d = np.linspace(-3, 3, 50)
X_contour_3d, Y_contour_3d = np.meshgrid(x_contour_3d, y_contour_3d)
Z_contour_3d = np.exp(-(X_contour_3d**2 + Y_contour_3d**2))

# 绘制等高线
ax.contour3D(X_contour_3d, Y_contour_3d, Z_contour_3d, 50, cmap='viridis')
ax.set_xlabel('X 轴')
ax.set_ylabel('Y 轴')
ax.set_zlabel('Z 轴')
ax.set_title('3D 等高线图')
plt.show()

动画

1. 基本动画

# 示例 33:基本动画
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots(figsize=(10, 6))
x_anim = np.linspace(0, 2*np.pi, 100)
line, = ax.plot(x_anim, np.sin(x_anim))

def animate(frame):
    line.set_ydata(np.sin(x_anim + frame * 0.1))
    return line,

ax.set_ylim(-1.5, 1.5)
ax.set_xlabel('X 轴')
ax.set_ylabel('Y 轴')
ax.set_title('动画示例')
ax.grid(True, alpha=0.3)

# 创建动画(保存为 HTML 或显示)
anim = FuncAnimation(fig, animate, frames=100, interval=50, blit=True)
plt.show()

# 如果要保存动画,取消下面的注释
# anim.save('animation.gif', writer='pillow', fps=20)

2. 实时数据更新动画

# 示例 34:实时数据更新
fig, ax = plt.subplots(figsize=(10, 6))
x_data = []
y_data = []
line, = ax.plot([], [], 'o-', linewidth=2, markersize=8)

ax.set_xlim(0, 10)
ax.set_ylim(-2, 2)
ax.set_xlabel('X 轴')
ax.set_ylabel('Y 轴')
ax.set_title('实时数据更新')
ax.grid(True, alpha=0.3)

def animate(frame):
    x_data.append(frame * 0.1)
    y_data.append(np.sin(frame * 0.1))
    line.set_data(x_data, y_data)
    if len(x_data) > 100:
        x_data.pop(0)
        y_data.pop(0)
    ax.set_xlim(max(0, frame * 0.1 - 10), max(10, frame * 0.1))
    return line,

anim = FuncAnimation(fig, animate, frames=200, interval=50, blit=True)
plt.show()

保存图片

1. 保存为不同格式

# 示例 35:保存图片
plt.figure(figsize=(10, 6))
plt.plot(x, y1, label='sin(x)', linewidth=2)
plt.plot(x, y2, label='cos(x)', linewidth=2)
plt.title('保存图片示例')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.legend()
plt.grid(True, alpha=0.3)

# 保存为 PNG(高分辨率)
plt.savefig('figure.png', dpi=300, bbox_inches='tight')

# 保存为 PDF(矢量图)
plt.savefig('figure.pdf', bbox_inches='tight')

# 保存为 SVG(矢量图)
plt.savefig('figure.svg', bbox_inches='tight')

# 保存为 JPG
plt.savefig('figure.jpg', dpi=300, bbox_inches='tight', quality=95)

print("图片已保存!")
plt.show()

2. 设置保存参数

# 示例 36:自定义保存参数
plt.figure(figsize=(10, 6))
plt.plot(x, y1, linewidth=2)
plt.title('自定义保存参数')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.grid(True, alpha=0.3)

# 保存时设置各种参数
plt.savefig(
    'custom_figure.png',
    dpi=300,                    # 分辨率
    bbox_inches='tight',        # 紧凑布局
    facecolor='white',          # 背景色
    edgecolor='none',           # 边框颜色
    format='png',               # 格式
    transparent=False           # 是否透明
)

plt.show()

实战案例

案例 1:股票价格可视化

# 案例 1:模拟股票价格数据可视化
np.random.seed(42)

# 生成模拟股票数据
dates_stock = pd.date_range('2024-01-01', periods=100, freq='D')
prices = 100 + np.cumsum(np.random.randn(100) * 2)
volumes = np.random.randint(1000000, 5000000, 100)

# 创建图表
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), 
                                gridspec_kw={'height_ratios': [3, 1]})

# 价格图
ax1.plot(dates_stock, prices, linewidth=2, color='#3498db', label='收盘价')
ax1.fill_between(dates_stock, prices, alpha=0.3, color='#3498db')
ax1.set_ylabel('价格 (元)', fontsize=12)
ax1.set_title('股票价格走势', fontsize=14, fontweight='bold')
ax1.legend()
ax1.grid(True, alpha=0.3)
ax1.set_xticklabels([])

# 成交量图
ax2.bar(dates_stock, volumes, color='#e74c3c', alpha=0.6, width=0.8)
ax2.set_xlabel('日期', fontsize=12)
ax2.set_ylabel('成交量', fontsize=12)
ax2.grid(True, alpha=0.3, axis='y')

# 格式化日期
fig.autofmt_xdate()

plt.tight_layout()
plt.show()

案例 2:销售数据分析仪表板

# 案例 2:销售数据分析仪表板
np.random.seed(42)

# 生成销售数据
months = ['1月', '2月', '3月', '4月', '5月', '6月']
products = ['产品A', '产品B', '产品C']
sales_data = np.random.randint(50, 200, (len(months), len(products)))

# 创建仪表板
fig = plt.figure(figsize=(16, 10))
gs = GridSpec(2, 3, figure=fig, hspace=0.3, wspace=0.3)

# 1. 月度销售趋势
ax1 = fig.add_subplot(gs[0, :2])
x_pos = np.arange(len(months))
width = 0.25
for i, product in enumerate(products):
    ax1.bar(x_pos + i*width, sales_data[:, i], width, label=product, alpha=0.8)
ax1.set_xlabel('月份')
ax1.set_ylabel('销售额')
ax1.set_title('月度销售趋势', fontweight='bold')
ax1.set_xticks(x_pos + width)
ax1.set_xticklabels(months)
ax1.legend()
ax1.grid(True, alpha=0.3, axis='y')

# 2. 产品占比
ax2 = fig.add_subplot(gs[0, 2])
total_sales = sales_data.sum(axis=0)
ax2.pie(total_sales, labels=products, autopct='%1.1f%%', startangle=90)
ax2.set_title('产品销售额占比', fontweight='bold')

# 3. 累计销售额
ax3 = fig.add_subplot(gs[1, :])
cumulative_sales = np.cumsum(sales_data, axis=0)
for i, product in enumerate(products):
    ax3.plot(months, cumulative_sales[:, i], marker='o', linewidth=2, label=product)
ax3.set_xlabel('月份')
ax3.set_ylabel('累计销售额')
ax3.set_title('累计销售额趋势', fontweight='bold')
ax3.legend()
ax3.grid(True, alpha=0.3)

plt.suptitle('销售数据分析仪表板', fontsize=16, fontweight='bold', y=0.98)
plt.show()

案例 3:多维度数据对比

# 案例 3:多维度数据对比
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 数据准备
categories_comp = ['Q1', 'Q2', 'Q3', 'Q4']
values_2023 = [120, 135, 150, 145]
values_2024 = [130, 145, 160, 155]

# 1. 柱状图对比
axes[0, 0].bar(np.arange(len(categories_comp)) - 0.2, values_2023, 
               width=0.4, label='2023', color='#3498db', alpha=0.8)
axes[0, 0].bar(np.arange(len(categories_comp)) + 0.2, values_2024, 
               width=0.4, label='2024', color='#e74c3c', alpha=0.8)
axes[0, 0].set_xlabel('季度')
axes[0, 0].set_ylabel('销售额')
axes[0, 0].set_title('季度销售额对比')
axes[0, 0].set_xticks(np.arange(len(categories_comp)))
axes[0, 0].set_xticklabels(categories_comp)
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3, axis='y')

# 2. 折线图对比
axes[0, 1].plot(categories_comp, values_2023, marker='o', linewidth=2, 
                label='2023', color='#3498db')
axes[0, 1].plot(categories_comp, values_2024, marker='s', linewidth=2, 
                label='2024', color='#e74c3c')
axes[0, 1].set_xlabel('季度')
axes[0, 1].set_ylabel('销售额')
axes[0, 1].set_title('季度趋势对比')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)

# 3. 增长率
growth_rate = [(v2024 - v2023) / v2023 * 100 for v2023, v2024 in zip(values_2023, values_2024)]
colors_growth = ['green' if x > 0 else 'red' for x in growth_rate]
axes[1, 0].bar(categories_comp, growth_rate, color=colors_growth, alpha=0.7)
axes[1, 0].axhline(y=0, color='black', linestyle='--', linewidth=1)
axes[1, 0].set_xlabel('季度')
axes[1, 0].set_ylabel('增长率 (%)')
axes[1, 0].set_title('同比增长率')
axes[1, 0].grid(True, alpha=0.3, axis='y')

# 4. 堆叠面积图
axes[1, 1].fill_between(categories_comp, 0, values_2023, alpha=0.6, 
                        label='2023', color='#3498db')
axes[1, 1].fill_between(categories_comp, values_2023, 
                        np.array(values_2023) + np.array(values_2024), 
                        alpha=0.6, label='2024', color='#e74c3c')
axes[1, 1].set_xlabel('季度')
axes[1, 1].set_ylabel('累计销售额')
axes[1, 1].set_title('累计销售额堆叠')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

最佳实践

1. 代码组织建议

# 最佳实践 1:创建可复用的绘图函数
def create_line_plot(x, y, title='', xlabel='', ylabel='', 
                     figsize=(10, 6), style='default'):
    """创建标准化的线图"""
    plt.style.use(style)
    fig, ax = plt.subplots(figsize=figsize)
    ax.plot(x, y, linewidth=2)
    ax.set_title(title, fontsize=14, fontweight='bold')
    ax.set_xlabel(xlabel, fontsize=12)
    ax.set_ylabel(ylabel, fontsize=12)
    ax.grid(True, alpha=0.3)
    plt.tight_layout()
    return fig, ax

# 使用
fig, ax = create_line_plot(x, y1, title='正弦函数', 
                           xlabel='X 轴', ylabel='Y 轴')
plt.show()

2. 性能优化

# 最佳实践 2:大数据量时的优化
# 对于大数据集,使用采样或降采样
large_x = np.linspace(0, 100, 100000)
large_y = np.sin(large_x)

# 方法1:降采样显示
sample_indices = np.arange(0, len(large_x), 100)
plt.figure(figsize=(10, 6))
plt.plot(large_x[sample_indices], large_y[sample_indices], linewidth=1)
plt.title('降采样后的数据')
plt.show()

# 方法2:使用更高效的绘图方法
# 对于散点图,使用较小的标记
plt.figure(figsize=(10, 6))
plt.scatter(large_x[::100], large_y[::100], s=1, alpha=0.5)
plt.title('优化的散点图')
plt.show()

3. 样式一致性

# 最佳实践 3:定义统一的样式
def apply_custom_style():
    """应用自定义样式"""
    plt.rcParams.update({
        'figure.figsize': (10, 6),
        'font.size': 11,
        'axes.labelsize': 12,
        'axes.titlesize': 14,
        'xtick.labelsize': 10,
        'ytick.labelsize': 10,
        'legend.fontsize': 11,
        'figure.titlesize': 16,
        'axes.grid': True,
        'grid.alpha': 0.3,
        'axes.spines.top': False,
        'axes.spines.right': False
    })

apply_custom_style()

plt.figure()
plt.plot(x, y1, label='sin(x)')
plt.plot(x, y2, label='cos(x)')
plt.title('统一样式示例')
plt.xlabel('X 轴')
plt.ylabel('Y 轴')
plt.legend()
plt.show()

4. 错误处理

# 最佳实践 4:添加错误处理
def safe_plot(x, y, title=''):
    """安全的绘图函数,包含错误处理"""
    try:
        if len(x) != len(y):
            raise ValueError("x 和 y 的长度必须相同")
        
        plt.figure(figsize=(10, 6))
        plt.plot(x, y)
        plt.title(title)
        plt.grid(True, alpha=0.3)
        plt.show()
    except Exception as e:
        print(f"绘图错误: {e}")

# 使用
safe_plot(x, y1, title='安全绘图示例')

5. 交互式绘图(可选)

# 最佳实践 5:使用交互式后端(需要安装 ipympl)
# %matplotlib widget  # 在 Jupyter Notebook 中使用

# 或者使用 plotly 进行交互式绘图(需要安装 plotly)
try:
    import plotly.graph_objects as go
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=x, y=y1, mode='lines', name='sin(x)'))
    fig.add_trace(go.Scatter(x=x, y=y2, mode='lines', name='cos(x)'))
    fig.update_layout(title='交互式图表', xaxis_title='X 轴', yaxis_title='Y 轴')
    fig.show()
except ImportError:
    print("plotly 未安装,跳过交互式示例")

总结

本文详细介绍了 Matplotlib 的使用方法,包括:

  1. 基础绘图:线图、散点图、柱状图等基本图表
  2. 常用图表类型:直方图、饼图、箱线图、热力图等
  3. 子图和布局:创建复杂的多子图布局
  4. 样式和美化:自定义图表外观
  5. 3D 绘图:3D 线图、散点图、曲面图
  6. 动画:创建动态图表
  7. 保存图片:保存为各种格式
  8. 实战案例:实际应用场景

关键要点

  • 理解架构:Figure、Axes、Axis 的关系
  • 选择合适的图表类型:根据数据特点选择
  • 保持一致性:使用统一的样式
  • 优化性能:大数据量时注意优化
  • 代码复用:创建可复用的绘图函数

进一步学习

  • 学习 Seaborn 进行更高级的统计可视化
  • 学习 Plotly 创建交互式图表
  • 学习 Bokeh 创建 Web 交互式可视化
  • 学习如何将 Matplotlib 图表集成到 Web 应用

评论