一、Matplotlib 核心对象与架构概览

Matplotlib 采用三层架构设计,理解其核心对象是高效绘图的基础。

层级 核心对象 功能与描述
Scripting Layer (脚本层) pyplot (plt) 模块 提供类似MATLAB的便捷接口,适合快速绘图和交互式使用。
Artist Layer (艺术家层) Figure, Axes, Artist 对象 面向对象API的核心。Figure是顶级容器,Axes是带有坐标系的绘图区域,Artist是图上所有可见元素(如线条、文本)的基类。
Backend Layer (后端层) 各种渲染器 (如 Agg, TkAgg, Qt5Agg) 负责将图形渲染到屏幕或文件。Agg后端用于生成静态图片(PNG, SVG等),是默认的无界面后端。

基础工作流程通常是先创建图形(Figure)和坐标系(Axes),然后在Axes上添加各种Artist元素,最后通过后端显示或保存。

import matplotlib.pyplot as plt
import numpy as np

# 1. 显式创建图形和坐标轴(面向对象风格,推荐)
fig, ax = plt.subplots()  # fig是Figure对象,ax是Axes对象
# 2. 在坐标轴ax上绘图
x = np.linspace(0, 2*np.pi, 100)
ax.plot(x, np.sin(x), label='sin(x)')  # 绘制线条,返回一个Line2D Artist对象
# 3. 设置图表属性
ax.set_xlabel('X Axis')
ax.set_ylabel('Y Axis')
ax.set_title('A Simple Plot')
ax.legend()
# 4. 显示图表
plt.show()

二、常用绘图函数详解

Axes对象提供了绝大多数绘图方法。下表列出了最常用的几种:

函数名 主要用途 关键参数示例 输出图形类型
plot() 绘制折线图/散点图 x, y, fmt='o-‘ (格式字符串), color=’r‘, linewidth=2, label=’series1‘ 线图、散点图
scatter() 绘制散点图(可定义点属性) x, y, s=50 (点大小), c=colors (颜色), marker=’^‘, alpha=0.6 散点图
bar() / barh() 绘制(垂直/水平)条形图 x, height, width=0.8, color=’skyblue‘, edgecolor=’black‘, tick_label=labels 条形图
hist() 绘制直方图(数据分布) data, bins=10 (箱数), density=True (归一化), color=’green‘, alpha=0.7, edgecolor=’black‘ 直方图
pie() 绘制饼图 x, labels=labels, autopct=’%1.1f%%‘ (百分比格式), startangle=90 饼图
imshow() 显示图像或2D数组(热力图) data, cmap=’viridis‘, aspect=’auto‘, origin=’upper‘ 热力图、图像
contour() / contourf() 绘制(填充)等高线图 X, Y, Z, levels=20, cmap=’coolwarm‘ 等高线图
boxplot() 绘制箱线图(数据分布统计) data, notch=True (缺口), vert=False (水平), patch_artist=True (填充) 箱线图
violinplot() 绘制小提琴图(结合箱型与核密度) data, showmeans=True (显示均值), showmedians=True 小提琴图

三、图表元素与样式设置核心功能

创建图形后,需对坐标轴、标题、图例等元素进行精细控制。

设置类别 常用函数/属性 说明与示例
坐标轴与刻度 ax.set_xlim() / ax.set_ylim() 设置坐标轴范围。ax.set_xlim(0, 10)
ax.set_xlabel() / ax.set_ylabel() 设置坐标轴标签。ax.set_xlabel(‘Time (s)’, fontsize=12)
ax.set_xticks() / ax.set_yticks() 设置刻度位置。ax.set_xticks([0, np.pi, 2*np.pi])
ax.set_xticklabels() 设置刻度标签。ax.set_xticklabels([‘0‘, ’π‘, ’2π‘])
ax.tick_params() 精细控制刻度参数。ax.tick_params(axis=’x‘, rotation=45, labelsize=10)
ax.grid() 添加网格。ax.grid(True, linestyle=’–‘, alpha=0.5)
标题与图例 ax.set_title() 设置子图标题。ax.set_title(‘Main Title‘, fontsize=14, loc=’left‘)
ax.legend() 显示图例。ax.legend(loc=’upper left‘, frameon=False, fontsize=’small‘)
文本与注解 ax.text() 在指定坐标添加文本。ax.text(2, 3, ’Important Point‘, fontsize=12)
ax.annotate() 添加带箭头的注解。ax.annotate(’Max Value‘, xy=(5, 1), xytext=(3, 1.5), arrowprops=dict(arrowstyle=’->‘))
样式与颜色 plt.style.use() 使用预设样式。plt.style.use(’seaborn-v0_8-darkgrid‘)
color / c 线条、标记、面的颜色。支持名称(‘red‘)、十六进制(‘#FF5733‘)、RGB元组。
linestyle / ls 线条样式。‘-‘ (实线), ’–‘ (虚线), ’:’ (点线), ’-.’ (点划线)
marker 数据点标记。‘o‘ (圆), ’s‘ (方形), ’^‘ (上三角), ’D‘ (菱形)
linewidth / lw 线宽。
markersize / ms 标记大小。
alpha 透明度 (0~1)。

四、多子图与图形布局管理

对于复杂仪表板,需要创建和管理多个子图。

方法 描述 示例
plt.subplots() 最常用。一次性创建网格状子图。 fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8)) axes是一个2x2的Axes数组。
plt.subplot() 按索引添加子图(MATLAB风格)。 plt.subplot(2, 2, 1) # 创建2行2列的第1个子图
fig.add_subplot() 面向对象方式添加子图。 ax1 = fig.add_subplot(2, 2, 1)
plt.subplot2grid() 创建非均匀网格布局。 ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3)
GridSpec 最灵活。用于创建复杂的、可跨行列的子图布局。 见下方实战代码。

五、实战示例:综合应用

以下代码综合运用上述函数,创建一个包含多种图表类型和复杂布局的仪表板。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec

# 设置中文字体(可选)和整体样式
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号
plt.style.use('seaborn-v0_8-talk')  # 使用一个美观的样式

# 1. 创建Figure和基于GridSpec的复杂布局
fig = plt.figure(figsize=(15, 10))
gs = GridSpec(3, 4, figure=fig, hspace=0.4, wspace=0.3)  # 3行4列,调整间距

# 2. 子图1:多线图 (占据第一行整行)
ax1 = fig.add_subplot(gs[0, :])  # 第0行,所有列
x = np.linspace(0, 10, 100)
for i in range(5):
    # 使用plot函数,设置不同的线型、颜色、标记
    ax1.plot(x, np.sin(x + i * 0.5), 
             label=f'Series {i+1}', 
             linewidth=1.5, 
             marker='o' if i%2==0 else None, 
             markersize=4, 
             alpha=0.8)
ax1.set_title('多系列折线图示例', fontsize=14, fontweight='bold')
ax1.set_xlabel('时间 / X轴')
ax1.set_ylabel('数值 / Y轴')
ax1.legend(loc='upper right', ncol=3, fontsize='small')
ax1.grid(True, alpha=0.3)

# 3. 子图2:分组条形图 (第二行,前两列)
ax2 = fig.add_subplot(gs[1, :2])
categories = ['产品A', '产品B', '产品C']
quarter1 = [20, 34, 30]
quarter2 = [25, 32, 34]
x_index = np.arange(len(categories))
width = 0.35
# 使用bar函数绘制分组条形
bars1 = ax2.bar(x_index - width/2, quarter1, width, label='Q1', color='skyblue', edgecolor='grey')
bars2 = ax2.bar(x_index + width/2, quarter2, width, label='Q2', color='lightcoral', edgecolor='grey')
ax2.set_title('季度销售额对比', fontsize=13)
ax2.set_xlabel('产品类别')
ax2.set_ylabel('销售额 (万)')
ax2.set_xticks(x_index)
ax2.set_xticklabels(categories)
ax2.legend()
# 在条形顶部添加数据标签
for bars in [bars1, bars2]:
    for bar in bars:
        height = bar.get_height()
        ax2.text(bar.get_x() + bar.get_width()/2., height + 0.5,
                 f'{height}', ha='center', va='bottom', fontsize=9)

# 4. 子图3:散点图与分类 (第二行,后两列)
ax3 = fig.add_subplot(gs[1, 2:])
np.random.seed(42)
n_points = 50
x_scatter = np.random.randn(n_points)
y_scatter = np.random.randn(n_points)
colors_scatter = np.random.rand(n_points)
sizes = 100 * np.random.rand(n_points)  # 点的大小数组
# 使用scatter函数,用颜色和大小传递第三、四维信息
scatter = ax3.scatter(x_scatter, y_scatter, c=colors_scatter, s=sizes, 
                      alpha=0.6, cmap='viridis', edgecolor='black', linewidth=0.5)
ax3.set_title('带颜色和尺寸编码的散点图', fontsize=13)
ax3.set_xlabel('特征 X')
ax3.set_ylabel('特征 Y')
# 添加颜色条
cbar = plt.colorbar(scatter, ax=ax3)
cbar.set_label('颜色值', rotation=270, labelpad=15)

# 5. 子图4:组合图表 (直方图+密度曲线) (第三行,第一列)
ax4 = fig.add_subplot(gs[2, 0])
data_hist = np.random.randn(1000)
# 使用hist函数绘制直方图,density参数使其变为概率密度
n, bins, patches = ax4.hist(data_hist, bins=30, density=True, alpha=0.7, 
                            color='steelblue', edgecolor='black')
# 在同一个ax上绘制核密度估计曲线
from scipy.stats import gaussian_kde
kde = gaussian_kde(data_hist)
x_kde = np.linspace(data_hist.min(), data_hist.max(), 200)
ax4.plot(x_kde, kde(x_kde), color='darkorange', linewidth=2, label='密度曲线')
ax4.set_title('数据分布直方图与密度曲线', fontsize=13)
ax4.set_xlabel('数值')
ax4.set_ylabel('概率密度')
ax4.legend()

# 6. 子图5:箱线图 (第三行,第二列)
ax5 = fig.add_subplot(gs[2, 1])
data_box = [np.random.normal(0, std, 100) for std in range(1, 5)]
# 使用boxplot函数,patch_artist=True允许填充颜色
box_plot = ax5.boxplot(data_box, patch_artist=True, notch=True,
                        labels=[f'Group {i+1}' for i in range(4)])
# 为每个箱体设置颜色
colors_box = ['lightgreen', 'lightblue', 'pink', 'wheat']
for patch, color in zip(box_plot['boxes'], colors_box):
    patch.set_facecolor(color)
ax5.set_title('多组数据箱线图对比', fontsize=13)
ax5.set_ylabel('观测值')
ax5.grid(True, axis='y', alpha=0.3)

# 7. 子图6:填充区域图 (第三行,第三列)
ax6 = fig.add_subplot(gs[2, 2])
x_fill = np.linspace(0, 10, 200)
y1_fill = np.sin(x_fill)
y2_fill = np.cos(x_fill)
# 使用fill_between函数填充区域
ax6.plot(x_fill, y1_fill, 'b', label='sin(x)', linewidth=1.5)
ax6.plot(x_fill, y2_fill, 'r', label='cos(x)', linewidth=1.5)
ax6.fill_between(x_fill, y1_fill, y2_fill, where=(y1_fill > y2_fill), 
                 color='blue', alpha=0.3, interpolate=True, label='sin > cos')
ax6.fill_between(x_fill, y1_fill, y2_fill, where=(y1_fill <= y2_fill), 
                 color='red', alpha=0.3, interpolate=True, label='sin <= cos')
ax6.set_title('函数间区域填充', fontsize=13)
ax6.set_xlabel('x')
ax6.legend(loc='upper right', fontsize='x-small')

# 8. 子图7:饼图 (第三行,第四列)
ax7 = fig.add_subplot(gs[2, 3])
sizes_pie = [15, 30, 45, 10]
labels_pie = ['A类', 'B类', 'C类', '其他']
explode = (0, 0.1, 0, 0)  # 突出第二块
# 使用pie函数,autopct设置百分比格式
wedges, texts, autotexts = ax7.pie(sizes_pie, explode=explode, labels=labels_pie, 
                                    autopct='%1.1f%%', startangle=90, 
                                    colors=plt.cm.Set3(np.arange(len(sizes_pie))/len(sizes_pie)))
# 美化文本
for autotext in autotexts:
    autotext.set_color('white')
    autotext.set_fontweight('bold')
ax7.set_title('市场份额分布饼图', fontsize=13)
ax7.axis('equal')  # 确保饼图是圆形

# 9. 为整个图形添加一个总标题
fig.suptitle('Matplotlib 常用图表综合仪表板', fontsize=16, fontweight='bold', y=0.98)

# 10. 调整布局并显示
plt.tight_layout()
plt.show()

六、高级技巧与输出

  • 保存图形:使用 fig.savefig(‘filename.png‘, dpi=300, bbox_inches=’tight‘)。支持 PNG, PDF, SVG, EPS 等格式。
  • 使用样式print(plt.style.available) 查看所有可用样式,使用 plt.style.use(’ggplot‘) 应用。
  • 配置参数:通过 plt.rcParams 字典进行全局设置,如 plt.rcParams[’figure.dpi‘] = 150

掌握这些核心函数、对象和设置方法,就能应对绝大多数使用 Matplotlib 创建静态可视化图表的需求。对于更复杂的交互式或地理图表,可考虑结合 Plotly、Pyecharts 等库。


参考来源

更多推荐