Matplotlib核心绘图技术详解:从基础图表到高级布局

Matplotlib核心绘图技术详解:从基础图表到高级布局

本文将详细介绍Matplotlib的核心绘图技术,重点讲解折线图样式定制、散点图密度估计、柱状图堆叠显示、多子图布局和图表保存功能。每个部分都配有完整的代码示例和详细解释。

1. 折线图样式定制

折线图是数据可视化中最常用的图表类型之一,通过定制其样式可以使数据趋势更加清晰直观。

1.1 基本折线图与样式参数

Matplotlib提供了丰富的参数来自定义折线图的外观,包括颜色、线型、标记等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import matplotlib.pyplot as plt
import numpy as np

# 设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

# 创建示例数据
x = np.linspace(0, 10, 20)
y1 = np.sin(x)
y2 = np.cos(x)

# 创建画布
plt.figure(figsize=(10, 6))

# 绘制两条不同样式的折线
plt.plot(x, y1,
color='red', # 线条颜色
linestyle='-', # 线型:实线
linewidth=2, # 线宽
marker='o', # 标记样式:圆形
markersize=8, # 标记大小
markerfacecolor='blue', # 标记填充颜色
markeredgecolor='darkblue', # 标记边缘颜色
markeredgewidth=2, # 标记边缘宽度
label='正弦曲线')

plt.plot(x, y2,
color='green', # 线条颜色
linestyle='--', # 线型:虚线
linewidth=2, # 线宽
marker='s', # 标记样式:正方形
markersize=8, # 标记大小
markerfacecolor='yellow', # 标记填充颜色
markeredgecolor='darkgreen', # 标记边缘颜色
markeredgewidth=2, # 标记边缘宽度
label='余弦曲线')

# 添加图表元素
plt.title('自定义样式的折线图示例', fontsize=14)
plt.xlabel('X轴', fontsize=12)
plt.ylabel('Y轴', fontsize=12)
plt.legend() # 显示图例
plt.grid(True, linestyle=':', alpha=0.7) # 添加网格线

# 显示图表
plt.show()

1.2 线型和标记样式汇总

Matplotlib支持多种线型和标记样式,可以通过简写符号快速设置:

常用线型: - '-''solid':实线(默认) - '--''dashed':虚线 - '-.''dashdot':点划线 - ':''dotted':点线

常用标记: - '.':点标记 - 'o':实心圆 - 's':正方形 - '^':上三角形 - 'v':下三角形 - '*':星号 - '+':加号 - 'x':X号

常用颜色: - 'b':蓝色 - 'g':绿色 - 'r':红色 - 'c':青色 - 'm':品红 - 'y':黄色 - 'k':黑色 - 'w':白色

使用格式字符串可以快速设置样式,格式为 [marker][line][color]

1
2
3
# 使用格式字符串简化样式设置
plt.plot(x, y1, 'o-r', label='格式字符串示例') # 圆形标记、红色实线
plt.plot(x, y2, 's--g', label='另一示例') # 正方形标记、绿色虚线

2. 散点图密度估计

当数据点过多时,散点图会出现重叠问题,密度估计可以帮助我们更好地理解数据的分布情况。

2.1 基本散点图与密度估计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde

# 生成模拟数据(有相关性的两个变量)
np.random.seed(42)
N = 1000
x = np.random.normal(size=N)
y = x * 3 + np.random.normal(size=N)

# 计算点密度
xy = np.vstack([x, y]) # 将两个维度的数据叠加
z = gaussian_kde(xy)(xy) # 建立概率密度分布,并计算每个样本点的概率密度

# 按密度值排序,以便密度最高的点最后绘制(避免被遮盖)
idx = z.argsort()
x_sorted, y_sorted, z_sorted = x[idx], y[idx], z[idx]

# 创建画布和子图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))

# 左图:普通散点图
scatter1 = ax1.scatter(x, y, alpha=0.6, s=20)
ax1.set_title('普通散点图', fontsize=14)
ax1.set_xlabel('X变量')
ax1.set_ylabel('Y变量')

# 右图:密度散点图
scatter2 = ax2.scatter(x_sorted, y_sorted, c=z_sorted, s=20, cmap='viridis')
ax2.set_title('密度散点图', fontsize=14)
ax2.set_xlabel('X变量')
ax2.set_ylabel('Y变量')

# 添加颜色条
cbar = plt.colorbar(scatter2, ax=ax2)
cbar.set_label('点密度')

# 调整布局
plt.tight_layout()
plt.show()

2.2 使用二维直方图显示密度

对于大数据集,二维直方图是另一种有效的密度可视化方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import matplotlib.pyplot as plt
import numpy as np

# 生成更大数据集
np.random.seed(42)
x = np.random.normal(0, 1, 10000)
y = np.random.normal(0, 1, 10000)

# 创建画布和子图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))

# 左图:二维直方图(热力图)
hist2d = ax1.hist2d(x, y, bins=50, cmap='Blues')
ax1.set_title('二维直方图(热力图)', fontsize=14)
ax1.set_xlabel('X变量')
ax1.set_ylabel('Y变量')

# 添加颜色条
cbar1 = plt.colorbar(hist2d[3], ax=ax1)
cbar1.set_label('点数')

# 右图:等高线图(密度轮廓)
# 先计算二维直方图
counts, xedges, yedges = np.histogram2d(x, y, bins=50)
xcenters = (xedges[:-1] + xedges[1:]) / 2
ycenters = (yedges[:-1] + yedges[1:]) / 2

# 绘制等高线
contour = ax2.contour(xcenters, ycenters, counts.T, levels=10, colors='black')
ax2.clabel(contour, inline=True, fontsize=8)
ax2.set_title('密度等高线图', fontsize=14)
ax2.set_xlabel('X变量')
ax2.set_ylabel('Y变量')

# 调整布局
plt.tight_layout()
plt.show()

3. 柱状图堆叠显示

堆叠柱状图适用于展示多个类别数据的构成比例,特别适合比较各部分在整体中的贡献。

3.1 基本堆叠柱状图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import matplotlib.pyplot as plt
import numpy as np

# 示例数据:不同季度三种产品的销售额
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
product_a = [20, 35, 30, 35]
product_b = [25, 32, 34, 20]
product_c = [15, 18, 22, 28]

# 计算堆叠的起始位置
product_b_bottom = np.array(product_a)
product_c_bottom = np.array(product_a) + np.array(product_b)

# 创建画布
plt.figure(figsize=(10, 6))

# 绘制堆叠柱状图
bars_a = plt.bar(quarters, product_a, label='产品A', color='skyblue')
bars_b = plt.bar(quarters, product_b, bottom=product_a, label='产品B', color='lightgreen')
bars_c = plt.bar(quarters, product_c, bottom=product_c_bottom, label='产品C', color='lightcoral')

# 添加数据标签
def add_value_labels(bars, bottom_values=None):
for i, bar in enumerate(bars):
height = bar.get_height()
if bottom_values is not None:
height = bottom_values[i] + height
plt.text(bar.get_x() + bar.get_width()/2., height,
f'{int(height)}', ha='center', va='bottom')

add_value_labels(bars_a)
add_value_labels(bars_b, product_a)
add_value_labels(bars_c, product_c_bottom)

# 添加图表元素
plt.title('季度销售额堆叠柱状图', fontsize=14)
plt.xlabel('季度')
plt.ylabel('销售额(万元)')
plt.legend()

# 显示图表
plt.show()

3.2 水平堆叠柱状图

水平堆叠柱状图适用于类别名称较长或类别较多的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import matplotlib.pyplot as plt
import numpy as np

# 示例数据:不同部门预算分配
departments = ['研发部', '市场部', '行政部', '财务部', '人力资源']
salaries = [40, 30, 25, 20, 22]
equipment = [20, 15, 10, 5, 8]
training = [10, 25, 5, 3, 15]
other = [5, 10, 8, 2, 5]

# 计算堆叠位置
equipment_bottom = np.array(salaries)
training_bottom = equipment_bottom + np.array(equipment)
other_bottom = training_bottom + np.array(training)

# 创建画布
plt.figure(figsize=(12, 8))

# 绘制水平堆叠柱状图
bars_salaries = plt.barh(departments, salaries, label='工资', color='lightblue')
bars_equipment = plt.barh(departments, equipment, left=salaries, label='设备', color='lightgreen')
bars_training = plt.barh(departments, training, left=equipment_bottom, label='培训', color='lightcoral')
bars_other = plt.barh(departments, other, left=training_bottom, label='其他', color='lightyellow')

# 添加数据标签
def add_h_value_labels(bars, left_values=None):
for i, bar in enumerate(bars):
width = bar.get_width()
xpos = bar.get_x() + width/2
if left_values is not None:
xpos = left_values[i] + width/2
plt.text(xpos, bar.get_y() + bar.get_height()/2,
f'{int(width)}', ha='center', va='center')

add_h_value_labels(bars_salaries)
add_h_value_labels(bars_equipment, salaries)
add_h_value_labels(bars_training, equipment_bottom)
add_h_value_labels(bars_other, training_bottom)

# 添加图表元素
plt.title('部门预算分配水平堆叠图', fontsize=14)
plt.xlabel('预算(万元)')
plt.ylabel('部门')
plt.legend()

# 调整布局
plt.tight_layout()
plt.show()

4. 多子图布局

多子图布局允许在单个图形中展示多个相关图表,便于比较和分析。

4.1 使用subplots()创建规整布局

plt.subplots()函数是创建多子图最常用的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import matplotlib.pyplot as plt
import numpy as np

# 创建示例数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.exp(-x/5)
categories = ['A', 'B', 'C', 'D']
values1 = [15, 25, 35, 10]
values2 = [20, 30, 25, 15]

# 创建2×2的子图布局
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
fig.suptitle('多子图布局示例', fontsize=16)

# 左上子图:折线图
axs[0, 0].plot(x, y1, 'b-', label='sin(x)')
axs[0, 0].plot(x, y2, 'r--', label='cos(x)')
axs[0, 0].set_title('三角函数折线图')
axs[0, 0].set_xlabel('X轴')
axs[0, 0].set_ylabel('Y轴')
axs[0, 0].legend()
axs[0, 0].grid(True, alpha=0.3)

# 右上子图:散点图
scatter = axs[0, 1].scatter(x[::5], y3[::5], c=y3[::5], cmap='viridis', s=50)
axs[0, 1].set_title('指数衰减散点图')
axs[0, 1].set_xlabel('X轴')
axs[0, 1].set_ylabel('Y轴')
plt.colorbar(scatter, ax=axs[0, 1])

# 左下子图:柱状图
x_index = np.arange(len(categories))
width = 0.35
bars1 = axs[1, 0].bar(x_index - width/2, values1, width, label='系列1', color='skyblue')
bars2 = axs[1, 0].bar(x_index + width/2, values2, width, label='系列2', color='lightcoral')
axs[1, 0].set_title('分组柱状图')
axs[1, 0].set_xlabel('类别')
axs[1, 0].set_ylabel('数值')
axs[1, 0].set_xticks(x_index)
axs[1, 0].set_xticklabels(categories)
axs[1, 0].legend()

# 右下子图:饼图
axs[1, 1].pie(values1, labels=categories, autopct='%1.1f%%', startangle=90)
axs[1, 1].set_title('饼图示例')

# 调整子图间距
plt.tight_layout()
plt.subplots_adjust(top=0.92)
plt.show()

4.2 复杂网格布局

对于更复杂的布局需求,可以使用gridspec模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np

# 创建数据
x = np.linspace(0, 10, 100)
y = np.sin(x)

# 创建复杂网格布局
fig = plt.figure(figsize=(12, 10))
gs = gridspec.GridSpec(3, 3) # 3行3列

# 创建不同大小的子图
# 顶部大图(占据第一行全部)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x, y, 'b-', linewidth=2)
ax1.set_title('顶部大图 - 正弦函数', fontsize=14)
ax1.grid(True, alpha=0.3)

# 左下中图(占据第二行前两列)
ax2 = fig.add_subplot(gs[1, :2])
ax2.plot(x, np.cos(x), 'r--', linewidth=2)
ax2.set_title('左下中图 - 余弦函数', fontsize=12)
ax2.grid(True, alpha=0.3)

# 右中小图(占据第二行第三列)
ax3 = fig.add_subplot(gs[1, 2])
ax3.pie([30, 25, 45], labels=['A', 'B', 'C'], autopct='%1.1f%%')
ax3.set_title('右中小图 - 饼图', fontsize=12)

# 底部小图(第三行分散排列)
ax4 = fig.add_subplot(gs[2, 0])
ax4.scatter(x[::10], y[::10], color='green')
ax4.set_title('散点图1', fontsize=10)

ax5 = fig.add_subplot(gs[2, 1])
ax5.scatter(x[::10], np.cos(x[::10]), color='purple')
ax5.set_title('散点图2', fontsize=10)

ax6 = fig.add_subplot(gs[2, 2])
ax6.bar(['X', 'Y', 'Z'], [25, 40, 35], color='orange')
ax6.set_title('柱状图', fontsize=10)

# 调整布局
plt.tight_layout()
plt.show()

5. 图表保存功能

正确保存图表是数据可视化工作流中的重要环节,Matplotlib支持多种格式和高质量输出。

5.1 基本保存功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import matplotlib.pyplot as plt
import numpy as np

# 创建示例图表
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

plt.figure(figsize=(10, 6))
plt.plot(x, y1, 'b-', label='sin(x)', linewidth=2)
plt.plot(x, y2, 'r--', label='cos(x)', linewidth=2)
plt.title('三角函数图表', fontsize=14)
plt.xlabel('X轴')
plt.ylabel('Y轴')
plt.legend()
plt.grid(True, alpha=0.3)

# 保存为不同格式
plt.savefig('basic_plot.png') # PNG格式(默认)
plt.savefig('basic_plot.jpg') # JPEG格式
plt.savefig('basic_plot.pdf') # PDF格式(矢量图)
plt.savefig('basic_plot.svg') # SVG格式(矢量图)

print("图表已保存为多种格式")
plt.show()

5.2 高质量保存设置

对于出版或专业报告,需要更高质量的图像输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import matplotlib.pyplot as plt
import numpy as np

# 创建高质量图表
x = np.linspace(0, 10, 200)
y = np.sin(x) * np.exp(-x/10)

# 设置高质量图形参数
plt.figure(figsize=(12, 8), dpi=300) # 高DPI提高分辨率

plt.plot(x, y, 'b-', linewidth=2.5, label='y = sin(x) × e^(-x/10)')
plt.title('高质量图表示例', fontsize=16, fontweight='bold')
plt.xlabel('X轴', fontsize=12)
plt.ylabel('Y轴', fontsize=12)
plt.legend(fontsize=11)
plt.grid(True, alpha=0.3)

# 高质量保存设置
plt.savefig('high_quality_plot.png',
dpi=300, # 高分辨率(每英寸点数)
bbox_inches='tight', # 紧贴内容,去除多余白边
facecolor='white', # 背景颜色
edgecolor='none', # 边框颜色
transparent=False) # 不透明

plt.savefig('high_quality_plot.pdf',
bbox_inches='tight',
facecolor='white',
edgecolor='none')

plt.savefig('transparent_bg.png',
bbox_inches='tight',
transparent=True) # 透明背景,适合嵌入其他文档

print("高质量图表已保存")
plt.show()

5.3 批量保存多个子图

当创建多个图表时,批量保存可以大大提高效率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import matplotlib.pyplot as plt
import numpy as np

# 创建多个图表并批量保存
chart_types = ['line', 'scatter', 'bar']
colors = ['blue', 'red', 'green']

for i, chart_type in enumerate(chart_types):
plt.figure(figsize=(8, 6))

x = np.linspace(0, 10, 50)
y = np.sin(x + i)

if chart_type == 'line':
plt.plot(x, y, color=colors[i], linewidth=2)
plt.title(f'折线图 {i+1}')
elif chart_type == 'scatter':
plt.scatter(x, y, color=colors[i], s=50)
plt.title(f'散点图 {i+1}')
elif chart_type == 'bar':
plt.bar(x[::5], y[::5], color=colors[i], width=0.5)
plt.title(f'柱状图 {i+1}')

plt.grid(True, alpha=0.3)

# 批量保存
filename = f'{chart_type}_chart_{i+1}.png'
plt.savefig(filename, dpi=150, bbox_inches='tight')
print(f'已保存: {filename}')

plt.close() # 关闭当前图形,释放内存

print("批量保存完成!")

总结

通过本教程,您已经掌握了Matplotlib的核心绘图技术:

  1. 折线图样式定制:学会了如何自定义颜色、线型、标记等属性,使折线图更加美观和易读。
  2. 散点图密度估计:掌握了使用高斯核密度估计和二维直方图来可视化大量数据的分布情况。
  3. 柱状图堆叠显示:了解了如何创建垂直和水平堆叠柱状图来展示数据的构成比例。
  4. 多子图布局:学会了使用subplots()gridspec创建复杂的多子图布局。
  5. 图表保存功能:掌握了如何以多种格式和质量设置保存图表。

这些技能是数据可视化工作的基础,结合实际项目多加练习,您将能够创建出更加专业和有效的数据可视化作品。