Matplotlib 中如何并排放置多个图表:全面指南
参考:Place plots side by side in Matplotlib
Matplotlib 是 Python 中最流行的数据可视化库之一,它提供了丰富的功能来创建各种类型的图表和绘图。在数据分析和科学研究中,我们经常需要比较多个数据集或展示多个相关的图表。这时,将多个图表并排放置就变得非常有用。本文将详细介绍如何在 Matplotlib 中实现并排放置多个图表,包括使用 subplot()、gridspec、add_subplot() 等多种方法,以及如何调整图表布局、大小和间距等细节。
1. 使用 subplot() 函数
subplot() 函数是 Matplotlib 中最基本和常用的创建子图的方法。它允许我们在一个图形窗口中创建多个子图,并指定它们的排列方式。
1.1 基本用法
subplot() 函数的基本语法是:
plt.subplot(nrows, ncols, index)
其中:
– nrows:行数
– ncols:列数
– index:当前子图的索引(从1开始)
让我们看一个简单的例子,创建两个并排的子图:
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, 4))
plt.subplot(1, 2, 1)
plt.plot(x, y1)
plt.title('Sine Wave - how2matplotlib.com')
plt.subplot(1, 2, 2)
plt.plot(x, y2)
plt.title('Cosine Wave - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个 1 行 2 列的子图布局。第一个 subplot() 调用创建了左侧的子图,第二个调用创建了右侧的子图。tight_layout() 函数用于自动调整子图之间的间距。
1.2 更复杂的布局
subplot() 函数也可以用来创建更复杂的布局。例如,我们可以创建一个 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.tan(x)
plt.figure(figsize=(10, 8))
plt.subplot(2, 2, 1)
plt.plot(x, y1)
plt.title('Sine - how2matplotlib.com')
plt.subplot(2, 2, 2)
plt.plot(x, y2)
plt.title('Cosine - how2matplotlib.com')
plt.subplot(2, 2, (3, 4))
plt.plot(x, y3)
plt.title('Tangent - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个 2×2 的网格。前两个子图分别占据了左上和右上的位置,而第三个子图通过 (3, 4) 参数跨越了底部两个位置。
2. 使用 subplots() 函数
subplots() 函数是一种更方便的创建多个子图的方法,特别是当你需要创建规则的网格布局时。
2.1 基本用法
subplots() 函数的基本语法是:
fig, axs = plt.subplots(nrows, ncols)
这将返回一个 Figure 对象和一个包含所有子图的 Axes 对象数组。
让我们看一个例子,创建一个 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.tan(x)
y4 = np.exp(x)
fig, axs = plt.subplots(2, 2, figsize=(10, 8))
axs[0, 0].plot(x, y1)
axs[0, 0].set_title('Sine - how2matplotlib.com')
axs[0, 1].plot(x, y2)
axs[0, 1].set_title('Cosine - how2matplotlib.com')
axs[1, 0].plot(x, y3)
axs[1, 0].set_title('Tangent - how2matplotlib.com')
axs[1, 1].plot(x, y4)
axs[1, 1].set_title('Exponential - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,axs 是一个 2×2 的 Axes 对象数组。我们可以通过索引来访问每个子图,并在其上绘制数据。
2.2 共享轴
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)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了两个垂直排列的子图,它们共享 x 轴。这意味着当你在一个子图上缩放或平移时,另一个子图的 x 轴也会相应地更新。
3. 使用 GridSpec
GridSpec 是 Matplotlib 中一个更灵活的子图布局管理器,它允许你创建复杂的、不规则的子图布局。
3.1 基本用法
以下是使用 GridSpec 创建子图的基本步骤:
- 创建一个 GridSpec 对象
- 使用 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)
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 - how2matplotlib.com')
ax2 = fig.add_subplot(gs[0, 1])
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
ax3 = fig.add_subplot(gs[1, :])
ax3.plot(x, y3)
ax3.set_title('Tangent - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个 2×2 的网格,但第三个子图跨越了底部的两个单元格。
3.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)
fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(3, 3)
ax1 = fig.add_subplot(gs[0, :2])
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2 = fig.add_subplot(gs[0, 2])
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
ax3 = fig.add_subplot(gs[1:, 0])
ax3.plot(x, y3)
ax3.set_title('Tangent - how2matplotlib.com')
ax4 = fig.add_subplot(gs[1:, 1:])
ax4.plot(x, y4)
ax4.set_title('Exponential - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个 3×3 的网格,但子图的大小和位置是不规则的。这种灵活性使得 GridSpec 成为创建复杂布局的强大工具。
4. 使用 add_subplot() 方法
add_subplot() 方法是另一种创建子图的方式,它允许我们在现有的 Figure 对象上添加新的子图。
4.1 基本用法
add_subplot() 方法的基本语法与 subplot() 函数类似:
ax = fig.add_subplot(nrows, ncols, index)
让我们看一个使用 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)
fig = plt.figure(figsize=(10, 4))
ax1 = fig.add_subplot(121)
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2 = fig.add_subplot(122)
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们首先创建了一个 Figure 对象,然后使用 add_subplot() 方法添加了两个并排的子图。
4.2 使用投影
add_subplot() 方法的一个优点是它允许我们为子图指定不同的投影,例如极坐标或 3D 投影:
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(0, 2*np.pi, 100)
r = np.sin(4*theta)
fig = plt.figure(figsize=(12, 5))
ax1 = fig.add_subplot(121, projection='polar')
ax1.plot(theta, r)
ax1.set_title('Polar Plot - how2matplotlib.com')
ax2 = fig.add_subplot(122, projection='3d')
x = np.sin(theta)
y = np.cos(theta)
z = theta
ax2.plot(x, y, z)
ax2.set_title('3D Plot - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何创建一个极坐标图和一个 3D 图,并将它们并排放置。
5. 调整子图布局
创建并排的子图后,我们可能需要调整它们的布局以优化显示效果。Matplotlib 提供了几种方法来实现这一点。
5.1 使用 tight_layout()
tight_layout() 函数是最简单的调整子图布局的方法。它会自动调整子图之间的间距,以避免重叠:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
tight_layout() 通常能够很好地处理大多数情况,但有时我们可能需要更精细的控制。
5.2 使用 subplots_adjust()
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)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
plt.subplots_adjust(left=0.1, right=0.95, wspace=0.3)
plt.show()
Output:
在这个例子中,我们调整了左边距、右边距和子图之间的水平间距。
5.3 使用 constrained_layout
constrained_layout 是 Matplotlib 3.0 引入的一个新特性,它提供了一种更智能的方式来调整子图布局:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4), constrained_layout=True)
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
plt.show()
Output:
constrained_layout 会自动调整子图的大小和位置,以确保标题、标签等元素不会重叠。
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.tan(x)
fig = plt.figure(figsize=(12, 4))
gs = gridspec.GridSpec(1, 3, width_ratios=[1, 2, 1])
ax1 = fig.add_subplot(gs[0])
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2 = fig.add_subplot(gs[1])
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
ax3 = fig.add_subplot(gs[2])
ax3.plot(x, y3)
ax3.set_title('Tangent - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了三个并排的子图,其中中间的子图是其他两个的两倍宽。
6.2 使用 add_gridspec()
add_gridspec() 是 Figure 对象的一个方法,它提供了类似于 GridSpec 的功能:
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)
fig = plt.figure(figsize=(12, 4))
gs = fig.add_gridspec(1, 3, width_ratios=[1, 2, 1])
ax1 = fig.add_subplot(gs[0])
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2 = fig.add_subplot(gs[1])
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
ax3 = fig.add_subplot(gs[2])
ax3.plot(x, y3)
ax3.set_title('Exponential - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个方法提供了与 GridSpec 类似的灵活性,但可以直接在 Figure 对象上调用。
7. 创建嵌套的子图
有时,我们可能需要在一个子图内部创建更多的子图。这可以通过嵌套使用 subplot() 或 gridspec 来实现。
7.1 使用嵌套的 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)
y4 = np.exp(x)
fig = plt.figure(figsize=(12, 8))
# 创建主子图
ax1 = fig.add_subplot(121)
ax1.plot(x, y1)
ax1.set_title('Main Plot: Sine - how2matplotlib.com')
# 创建嵌套子图
ax2 = fig.add_subplot(222)
ax2.plot(x, y2)
ax2.set_title('Nested: Cosine - how2matplotlib.com')
ax3 = fig.add_subplot(224)
ax3.plot(x, y3)
ax3.set_title('Nested: Tangent - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们在右侧创建了两个嵌套的子图。
7.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)
fig = plt.figure(figsize=(12, 8))
outer_grid = gridspec.GridSpec(1, 2)
ax1 = fig.add_subplot(outer_grid[0])
ax1.plot(x, y1)
ax1.set_title('Main Plot: Sine - how2matplotlib.com')
inner_grid = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=outer_grid[1])
ax2 = fig.add_subplot(inner_grid[0])
ax2.plot(x, y2)
ax2.set_title('Nested: Cosine - how2matplotlib.com')
ax3 = fig.add_subplot(inner_grid[1])
ax3.plot(x, y3)
ax3.set_title('Nested: Tangent - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何使用嵌套的 GridSpec 来创建更复杂的布局。
8. 调整子图间距
除了使用 tight_layout() 和 subplots_adjust(),我们还可以通过其他方法来精细调整子图之间的间距。
8.1 使用 gridspec_kw
在创建子图时,我们可以使用 gridspec_kw 参数来调整间距:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4),
gridspec_kw={'wspace': 0.3, 'hspace': 0.5})
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
plt.show()
Output:
在这个例子中,我们通过 gridspec_kw 参数调整了水平和垂直间距。
8.2 使用 set_position()
对于更精细的控制,我们可以使用 set_position() 方法直接设置每个子图的位置:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax1.set_position([0.1, 0.1, 0.4, 0.8]) # [left, bottom, width, height]
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
ax2.set_position([0.55, 0.1, 0.4, 0.8])
plt.show()
Output:
这种方法给予了我们对子图位置的完全控制。
9. 创建不同类型的并排图表
并排放置的子图不一定要是相同类型的。我们可以混合使用不同类型的图表来展示多维数据或不同的数据特征。
9.1 线图和散点图
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.random.normal(0, 0.1, 100)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot(x, y1)
ax1.set_title('Line Plot: Sine - how2matplotlib.com')
ax2.scatter(x, y2)
ax2.set_title('Scatter Plot: Random - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何并排放置一个线图和一个散点图。
9.2 柱状图和饼图
import matplotlib.pyplot as plt
import numpy as np
categories = ['A', 'B', 'C', 'D']
values = [25, 40, 20, 15]
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.bar(categories, values)
ax1.set_title('Bar Chart - how2matplotlib.com')
ax2.pie(values, labels=categories, autopct='%1.1f%%')
ax2.set_title('Pie Chart - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何并排放置一个柱状图和一个饼图。
10. 共享轴和刻度
当并排放置多个子图时,有时我们可能希望它们共享相同的轴或刻度,以便更容易比较数据。
10.1 共享 x 轴
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
ax1.plot(x, y1)
ax1.set_title('Sine - how2matplotlib.com')
ax2.plot(x, y2)
ax2.set_title('Cosine - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,两个子图共享相同的 x 轴,这使得比较两个函数变得更容易。
10.2 共享 y 轴
import matplotlib.pyplot as plt
import numpy as np
x1 = np.linspace(0, 10, 100)
x2 = np.linspace(0, 5, 100)
y = np.sin(x1)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4), sharey=True)
ax1.plot(x1, y)
ax1.set_title('Full Range - how2matplotlib.com')
ax2.plot(x2, np.sin(x2))
ax2.set_title('Half Range - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何让两个子图共享相同的 y 轴刻度。
结论
在 Matplotlib 中并排放置多个图表是一项强大的技能,它允许我们在一个图形中展示和比较多个数据集或不同类型的可视化。通过使用 subplot()、subplots()、GridSpec 和其他相关函数,我们可以创建各种复杂的布局来满足不同的数据展示需求。
本文详细介绍了多种创建并排图表的方法,包括基本的 subplot() 函数、更灵活的 GridSpec、以及如何调整子图大小和间距。我们还探讨了如何创建嵌套的子图、混合不同类型的图表,以及如何共享轴和刻度。
掌握这些技巧将使你能够创建更加丰富和信息量大的数据可视化,从而更有效地传达你的数据分析结果。记住,选择合适的布局和图表类型对于清晰地展示你的数据至关重要。通过实践和实验,你将能够找到最适合你的数据和目标受众的可视化方式。
最后,虽然本文提供了许多示例和技巧,但 Matplotlib 的功能远不止于此。随着你对库的深入了解,你会发现更多高级功能和自定义选项,这些都可以帮助你创建更加专业和吸引人的数据可视化。继续探索和学习,你将能够充分利用 Matplotlib 的强大功能,创建出令人印象深刻的数据可视化作品。