Matplotlib中绘制多个子图的全面指南

Matplotlib中绘制多个子图的全面指南

参考:Plot multiple plots in Matplotlib

Matplotlib是Python中最流行的数据可视化库之一,它提供了强大的工具来创建各种类型的图表和绘图。在数据分析和科学研究中,我们经常需要在同一个图形窗口中展示多个相关的图表。Matplotlib提供了多种方法来实现这一目标,使我们能够轻松地创建复杂的多子图布局。本文将详细介绍如何在Matplotlib中绘制多个子图,包括使用subplot()函数、GridSpec对象、add_subplot()方法等多种技术,以及如何自定义子图布局和样式。

1. 使用subplot()函数创建基本的多子图布局

subplot()函数是Matplotlib中最简单和最常用的创建多子图的方法之一。它允许我们将图形窗口划分为行和列,然后在指定的位置放置子图。

1.1 基本用法

subplot()函数的基本语法如下:

plt.subplot(nrows, ncols, index)

其中:
– nrows:子图布局中的行数
– ncols:子图布局中的列数
– index:当前子图的位置索引(从1开始)

让我们看一个简单的例子,创建一个2×2的子图布局:

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/10)
y4 = np.log(x + 1)

# 创建2x2的子图布局
plt.figure(figsize=(10, 8))

plt.subplot(2, 2, 1)
plt.plot(x, y1)
plt.title('Sine Wave - how2matplotlib.com')

plt.subplot(2, 2, 2)
plt.plot(x, y2)
plt.title('Cosine Wave - how2matplotlib.com')

plt.subplot(2, 2, 3)
plt.plot(x, y3)
plt.title('Exponential Decay - how2matplotlib.com')

plt.subplot(2, 2, 4)
plt.plot(x, y4)
plt.title('Logarithmic Growth - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,我们使用subplot()函数创建了一个2×2的子图布局。每个子图都有自己的标题,展示了不同的数学函数。plt.tight_layout()函数用于自动调整子图之间的间距,以避免重叠。

1.2 使用三位数表示法

subplot()函数还支持使用三位数来表示子图的位置,这种方法更加简洁:

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.tan(x)

plt.figure(figsize=(12, 4))

plt.subplot(131)
plt.plot(x, y1)
plt.title('Sine - how2matplotlib.com')

plt.subplot(132)
plt.plot(x, y2)
plt.title('Cosine - how2matplotlib.com')

plt.subplot(133)
plt.plot(x, y3)
plt.title('Tangent - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,131表示1行3列的布局中的第1个子图,132表示第2个子图,133表示第3个子图。这种表示方法更加简洁,适用于简单的布局。

2. 使用GridSpec创建灵活的子图布局

虽然subplot()函数很方便,但它在创建复杂布局时可能会受到限制。GridSpec对象提供了更灵活的方式来创建子图布局,允许我们精确控制每个子图的大小和位置。

2.1 基本用法

以下是使用GridSpec创建子图布局的基本示例:

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

# 创建示例数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.exp(-x/5)

# 创建图形和GridSpec对象
fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(2, 2)

# 创建子图
ax1 = fig.add_subplot(gs[0, 0])
ax1.plot(x, y1)
ax1.set_title('Sine Wave - how2matplotlib.com')

ax2 = fig.add_subplot(gs[0, 1])
ax2.plot(x, y2)
ax2.set_title('Cosine Wave - how2matplotlib.com')

ax3 = fig.add_subplot(gs[1, :])
ax3.plot(x, y3)
ax3.set_title('Exponential Decay - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,我们创建了一个2×2的网格,但第三个子图跨越了底部的两个单元格。这种灵活性允许我们创建更复杂的布局。

2.2 不规则网格布局

GridSpec还允许我们创建不规则的网格布局,例如:

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

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.tan(x)
y4 = np.exp(-x/5)

fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(3, 3)

ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x, y1)
ax1.set_title('Sine Wave - how2matplotlib.com')

ax2 = fig.add_subplot(gs[1, :2])
ax2.plot(x, y2)
ax2.set_title('Cosine Wave - how2matplotlib.com')

ax3 = fig.add_subplot(gs[1:, 2])
ax3.plot(x, y3)
ax3.set_title('Tangent - how2matplotlib.com')

ax4 = fig.add_subplot(gs[2, :2])
ax4.plot(x, y4)
ax4.set_title('Exponential Decay - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

这个例子展示了如何创建一个不规则的网格布局,其中一些子图跨越多个单元格。这种方法非常适合创建复杂的、自定义的图表布局。

3. 使用add_subplot()方法

add_subplot()方法是另一种创建子图的方式,它允许我们更精细地控制子图的位置和大小。

3.1 基本用法

以下是使用add_subplot()方法创建子图的基本示例:

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)
y4 = np.log(x + 1)

# 创建图形
fig = plt.figure(figsize=(12, 8))

# 添加子图
ax1 = fig.add_subplot(221)
ax1.plot(x, y1)
ax1.set_title('Sine Wave - how2matplotlib.com')

ax2 = fig.add_subplot(222)
ax2.plot(x, y2)
ax2.set_title('Cosine Wave - how2matplotlib.com')

ax3 = fig.add_subplot(223)
ax3.plot(x, y3)
ax3.set_title('Exponential Decay - how2matplotlib.com')

ax4 = fig.add_subplot(224)
ax4.plot(x, y4)
ax4.set_title('Logarithmic Growth - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

这个例子创建了一个2×2的子图布局,类似于使用subplot()函数的效果。但add_subplot()方法返回一个Axes对象,这使得我们可以更方便地自定义每个子图。

3.2 创建不规则布局

add_subplot()方法也可以用来创建不规则的布局:

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.tan(x)

fig = plt.figure(figsize=(12, 8))

ax1 = fig.add_subplot(211)
ax1.plot(x, y1)
ax1.set_title('Sine Wave - how2matplotlib.com')

ax2 = fig.add_subplot(223)
ax2.plot(x, y2)
ax2.set_title('Cosine Wave - how2matplotlib.com')

ax3 = fig.add_subplot(224)
ax3.plot(x, y3)
ax3.set_title('Tangent - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,我们创建了一个上方占据整个宽度的大子图,下方是两个并排的小子图。

4. 使用plt.subplots()函数

plt.subplots()函数提供了一种更简洁的方式来创建包含多个子图的图形。它返回一个图形对象和一个包含所有子图的数组。

4.1 基本用法

以下是使用plt.subplots()创建子图的基本示例:

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)
y4 = np.log(x + 1)

fig, axs = plt.subplots(2, 2, figsize=(12, 8))

axs[0, 0].plot(x, y1)
axs[0, 0].set_title('Sine Wave - how2matplotlib.com')

axs[0, 1].plot(x, y2)
axs[0, 1].set_title('Cosine Wave - how2matplotlib.com')

axs[1, 0].plot(x, y3)
axs[1, 0].set_title('Exponential Decay - how2matplotlib.com')

axs[1, 1].plot(x, y4)
axs[1, 1].set_title('Logarithmic Growth - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

这个方法创建了一个2×2的子图网格,并返回一个包含所有子图的二维数组axs。我们可以通过索引来访问和自定义每个子图。

4.2 共享轴

plt.subplots()函数还允许我们创建共享x轴或y轴的子图:

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.tan(x)

fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(10, 12), sharex=True)

ax1.plot(x, y1)
ax1.set_title('Sine Wave - how2matplotlib.com')

ax2.plot(x, y2)
ax2.set_title('Cosine Wave - how2matplotlib.com')

ax3.plot(x, y3)
ax3.set_title('Tangent - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,我们创建了三个垂直排列的子图,它们共享相同的x轴。这对于比较具有相同x轴范围的多个数据集非常有用。

5. 自定义子图布局

除了使用预定义的布局,我们还可以通过调整子图的位置和大小来创建完全自定义的布局。

5.1 使用add_axes()方法

add_axes()方法允许我们通过指定子图在图形中的位置和大小来创建子图:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(10, 8))

# 主子图
ax1 = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax1.plot(x, y1)
ax1.set_title('Main Plot: Sine Wave - how2matplotlib.com')

# 嵌入的小子图
ax2 = fig.add_axes([0.2, 0.6, 0.25, 0.25])
ax2.plot(x, y2)
ax2.set_title('Inset: Cosine Wave - how2matplotlib.com')

plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,我们创建了一个大的主子图和一个嵌入其中的小子图。add_axes()方法的参数[left, bottom, width, height]指定了子图在图形中的位置和大小,这些值都是相对于整个图形的比例。

5.2 调整子图间距

我们可以使用subplots_adjust()函数来调整子图之间的间距:

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)
y4 = np.log(x + 1)

fig, axs = plt.subplots(2, 2, figsize=(12, 8))

axs[0, 0].plot(x, y1)
axs[0, 0].set_title('Sine Wave - how2matplotlib.com')

axs[0, 1].plot(x, y2)
axs[0, 1].set_title('Cosine Wave - how2matplotlib.com')

axs[1, 0].plot(x, y3)
axs[1, 0].set_title('Exponential Decay - how2matplotlib.com')

axs[1, 1].plot(x, y4)
axs[1, 1].set_title('Logarithmic Growth - how2matplotlib.com')

plt.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.05, wspace=0.3, hspace=0.4)
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,我们使用subplots_adjust()函数来调整子图的位置和间距。参数含义如下:
– left, right, top, bottom:分别控制整个子图区域的左、右、上、下边界
– wspace:控制子图之间的水平间距
– hspace:控制子图之间的垂直间距

6. 创建不同大小的子图

有时我们需要创建大小不同的子图,这可以通过GridSpec或add_gridspec()方法实现。

6.1 使用GridSpec创建不同大小的子图

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

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.exp(-x/5)

fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(2, 2, width_ratios=[2, 1], height_ratios=[1, 2])

ax1 = fig.add_subplot(gs[0, 0])
ax1.plot(x, y1)
ax1.set_title('Sine Wave - how2matplotlib.com')

ax2 = fig.add_subplot(gs[0, 1])
ax2.plot(x, y2)
ax2.set_title('Cosine Wave - how2matplotlib.com')

ax3 = fig.add_subplot(gs[1, :])
ax3.plot(x, y3)
ax3.set_title('Exponential Decay - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,我们使用GridSpec创建了一个2×2的网格,但指定了不同的宽度比和高度比。结果是左上角的子图比右上角的子图宽,底部的子图跨越了整个宽度。

6.2 使用add_gridspec()方法

add_gridspec()是Figure对象的一个方法,提供了另一种创建不规则网格的方式:

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.tan(x)
y4 = np.exp(-x/5)

fig = plt.figure(figsize=(12, 8))
gs = fig.add_gridspec(3, 3)

ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x, y1)
ax1.set_title('Sine Wave - how2matplotlib.com')

ax2 = fig.add_subplot(gs[1, :-1])
ax2.plot(x, y2)
ax2.set_title('Cosine Wave - how2matplotlib.com')

ax3 = fig.add_subplot(gs[1:, -1])
ax3.plot(x, y3)
ax3.set_title('Tangent - how2matplotlib.com')

ax4 = fig.add_subplot(gs[-1, 0])
ax4.plot(x, y4)
ax4.set_title('Exponential Decay - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

这个例子创建了一个3×3的网格,但子图的大小和位置是不规则的。这种方法提供了极大的灵活性,允许我们创建复杂的自定义布局。

7. 在子图中嵌入子图

有时我们可能需要在一个子图中嵌入另一个子图,这可以通过inset_axes()函数实现。

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1.inset_locator import inset_axes

x = np.linspace(0, 10, 1000)
y = np.sin(x) * np.exp(-x/10)

fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y)
ax.set_title('Main Plot - how2matplotlib.com')

# 创建嵌入的子图
axins = inset_axes(ax, width="40%", height="30%", loc='lower left',
                   bbox_to_anchor=(0.5, 0.1, 0.5, 0.5),
                   bbox_transform=ax.transAxes)

# 在嵌入的子图中绘制放大的部分
axins.plot(x, y)
axins.set_xlim(2, 4)
axins.set_ylim(0.3, 0.8)
axins.set_title('Zoomed In - how2matplotlib.com')

plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,我们在主图中嵌入了一个小的子图,显示了主图中某个区域的放大视图。这种技术对于突出显示数据的特定部分非常有用。

8. 创建3D子图

Matplotlib还支持创建3D子图,这对于可视化三维数据非常有用。

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(12, 5))

# 2D子图
ax1 = fig.add_subplot(121)
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax1.plot(x, y)
ax1.set_title('2D Plot - how2matplotlib.com')

# 3D子图
ax2 = fig.add_subplot(122, 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))
ax2.plot_surface(X, Y, Z)
ax2.set_title('3D Plot - how2matplotlib.com')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

这个例子展示了如何在同一个图形中创建2D和3D子图。3D子图使用plot_surface()方法来绘制三维表面。

9. 子图中的多个图例

当一个子图中包含多条线或多个数据系列时,我们可能需要为每个系列添加图例。以下是一个示例:

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)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))

# 第一个子图
ax1.plot(x, y1, label='Sine')
ax1.plot(x, y2, label='Cosine')
ax1.set_title('Trigonometric Functions - how2matplotlib.com')
ax1.legend()

# 第二个子图
line1, = ax2.plot(x, y1, label='Sine')
line2, = ax2.plot(x, y2, label='Cosine')
line3, = ax2.plot(x, y3, label='Exponential')
ax2.set_title('Multiple Functions - how2matplotlib.com')

# 创建自定义图例
legend1 = ax2.legend(handles=[line1], loc='upper right')
ax2.add_artist(legend1)
legend2 = ax2.legend(handles=[line2, line3], loc='lower right')

plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

在这个例子中,第一个子图使用了标准的legend()方法,而第二个子图展示了如何创建多个自定义位置的图例。

10. 子图中的双Y轴

有时我们需要在同一个子图中显示具有不同范围的两组数据,这时可以使用双Y轴:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.exp(x)

fig, ax1 = plt.subplots(figsize=(10, 6))

color = 'tab:blue'
ax1.set_xlabel('X axis')
ax1.set_ylabel('Sine', color=color)
ax1.plot(x, y1, color=color)
ax1.tick_params(axis='y', labelcolor=color)

ax2 = ax1.twinx()  # 创建共享X轴的第二个Y轴
color = 'tab:orange'
ax2.set_ylabel('Exponential', color=color)
ax2.plot(x, y2, color=color)
ax2.tick_params(axis='y', labelcolor=color)

plt.title('Dual Y-axis Plot - how2matplotlib.com')
plt.tight_layout()
plt.show()

Output:

Matplotlib中绘制多个子图的全面指南

这个例子展示了如何在一个子图中创建两个Y轴,分别用于显示正弦函数和指数函数。这种技术对于比较具有不同数量级的数据非常有用。

结论

Matplotlib提供了丰富的工具和方法来创建多子图布局,从简单的网格布局到复杂的自定义布局。通过本文介绍的各种技术,你应该能够创建出适合你需求的任何类型的多子图布局。记住,实践是掌握这些技能的关键。尝试不同的方法,组合使用各种技术,你会发现Matplotlib在数据可视化方面的强大和灵活性。

无论是用于科学研究、数据分析还是商业报告,掌握这些多子图绘制技术都将大大提升你的数据可视化能力。继续探索和实验,你会发现更多Matplotlib的强大功能,为你的数据讲述更加丰富和引人入胜的故事。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程