Matplotlib中plt.subplots的全面指南:创建灵活的子图布局
参考:plt.subplots
plt.subplots是Matplotlib库中一个强大而灵活的函数,用于创建包含多个子图的图形布局。它允许用户轻松地在一个图形窗口中组织和排列多个图表,非常适合用于数据可视化和科学绘图。本文将深入探讨plt.subplots的各种用法、参数和技巧,帮助你充分利用这个功能来创建复杂而美观的图表布局。
1. plt.subplots的基本用法
plt.subplots函数的基本语法如下:
fig, ax = plt.subplots(nrows, ncols, figsize=(width, height))
其中:
– fig:返回的Figure对象,代表整个图形
– ax:返回的Axes对象或Axes对象的数组,代表子图
– nrows:子图的行数
– ncols:子图的列数
– figsize:图形的尺寸,以英寸为单位
让我们从一个简单的例子开始:
import matplotlib.pyplot as plt
import numpy as np
# 创建一个2x2的子图布局
fig, axs = plt.subplots(2, 2, figsize=(10, 8))
# 在每个子图中绘制不同的内容
x = np.linspace(0, 10, 100)
axs[0, 0].plot(x, np.sin(x))
axs[0, 0].set_title('Sine Wave - how2matplotlib.com')
axs[0, 1].plot(x, np.cos(x))
axs[0, 1].set_title('Cosine Wave - how2matplotlib.com')
axs[1, 0].plot(x, np.exp(x))
axs[1, 0].set_title('Exponential Function - how2matplotlib.com')
axs[1, 1].plot(x, np.log(x))
axs[1, 1].set_title('Logarithmic Function - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个2×2的子图布局。axs是一个2D数组,我们可以通过索引来访问每个子图。我们在每个子图中绘制了不同的数学函数,并为每个子图设置了标题。
2. 调整子图布局
plt.subplots提供了多个参数来调整子图的布局:
2.1 figsize参数
figsize参数用于设置整个图形的大小,单位为英寸。例如:
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
x = np.linspace(0, 10, 100)
for i in range(2):
for j in range(2):
axs[i, j].plot(x, np.sin(x + i + j))
axs[i, j].set_title(f'Sine Wave {i+1},{j+1} - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们将图形的大小设置为12×10英寸,这样可以得到一个更大的图形。
2.2 subplot_kw参数
subplot_kw参数允许我们为所有子图设置相同的关键字参数。例如:
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(10, 8), subplot_kw={'facecolor': 'lightgray'})
x = np.linspace(0, 10, 100)
for i in range(2):
for j in range(2):
axs[i, j].plot(x, np.sin(x + i + j))
axs[i, j].set_title(f'Sine Wave {i+1},{j+1} - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们使用subplot_kw参数为所有子图设置了浅灰色的背景。
2.3 gridspec_kw参数
gridspec_kw参数允许我们更精细地控制子图的布局。例如:
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(10, 8),
gridspec_kw={'width_ratios': [2, 1], 'height_ratios': [1, 2]})
x = np.linspace(0, 10, 100)
for i in range(2):
for j in range(2):
axs[i, j].plot(x, np.sin(x + i + j))
axs[i, j].set_title(f'Sine Wave {i+1},{j+1} - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们使用gridspec_kw参数设置了不同的宽度比和高度比,使得左列的子图比右列宽,下行的子图比上行高。
3. 创建不同形状的子图布局
plt.subplots不仅可以创建规则的网格布局,还可以创建不同形状的子图布局。
3.1 创建单行或单列的子图
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(1, 3, figsize=(15, 5))
x = np.linspace(0, 10, 100)
for i in range(3):
axs[i].plot(x, np.sin(x + i))
axs[i].set_title(f'Sine Wave {i+1} - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个包含3个子图的单行布局。
3.2 创建不规则的子图布局
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 3, figsize=(15, 10))
x = np.linspace(0, 10, 100)
for i in range(2):
for j in range(3):
axs[i, j].plot(x, np.sin(x + i + j))
axs[i, j].set_title(f'Sine Wave {i+1},{j+1} - how2matplotlib.com')
# 移除一些子图
fig.delaxes(axs[1, 2])
fig.delaxes(axs[1, 1])
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们首先创建了一个2×3的子图布局,然后使用fig.delaxes()方法移除了一些子图,从而创建了一个不规则的布局。
4. 共享轴
plt.subplots允许子图之间共享x轴或y轴,这在比较多个相关数据集时非常有用。
4.1 共享x轴
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8), sharex=True)
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title('Sine Wave - how2matplotlib.com')
ax2.plot(x, np.cos(x))
ax2.set_title('Cosine Wave - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了两个垂直排列的子图,并通过设置sharex=True使它们共享x轴。
4.2 共享y轴
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6), sharey=True)
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title('Sine Wave - how2matplotlib.com')
ax2.plot(x, np.cos(x))
ax2.set_title('Cosine Wave - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子创建了两个水平排列的子图,并通过设置sharey=True使它们共享y轴。
5. 调整子图间距
plt.subplots提供了几个参数来调整子图之间的间距:
5.1 使用hspace和wspace
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(10, 8))
x = np.linspace(0, 10, 100)
for i in range(2):
for j in range(2):
axs[i, j].plot(x, np.sin(x + i + j))
axs[i, j].set_title(f'Sine Wave {i+1},{j+1} - how2matplotlib.com')
plt.subplots_adjust(hspace=0.5, wspace=0.5)
plt.show()
Output:
在这个例子中,我们使用plt.subplots_adjust()函数来增加子图之间的水平和垂直间距。
5.2 使用gridspec_kw
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(10, 8),
gridspec_kw={'hspace': 0.4, 'wspace': 0.4})
x = np.linspace(0, 10, 100)
for i in range(2):
for j in range(2):
axs[i, j].plot(x, np.sin(x + i + j))
axs[i, j].set_title(f'Sine Wave {i+1},{j+1} - how2matplotlib.com')
plt.show()
Output:
这个例子展示了如何使用gridspec_kw参数来调整子图间距。
6. 创建不同大小的子图
有时我们可能需要创建大小不同的子图。这可以通过gridspec_kw参数来实现:
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(12, 10),
gridspec_kw={'height_ratios': [2, 1], 'width_ratios': [1, 2]})
x = np.linspace(0, 10, 100)
axs[0, 0].plot(x, np.sin(x))
axs[0, 0].set_title('Sine Wave - how2matplotlib.com')
axs[0, 1].plot(x, np.cos(x))
axs[0, 1].set_title('Cosine Wave - how2matplotlib.com')
axs[1, 0].plot(x, np.exp(x))
axs[1, 0].set_title('Exponential Function - how2matplotlib.com')
axs[1, 1].plot(x, np.log(x))
axs[1, 1].set_title('Logarithmic Function - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个2×2的子图布局,其中上面的子图比下面的高,右边的子图比左边的宽。
7. 创建嵌套的子图
plt.subplots还可以用来创建嵌套的子图布局:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 8))
# 创建主子图
gs = fig.add_gridspec(2, 2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1])
ax3 = fig.add_subplot(gs[1, :])
# 在右上角的子图中创建嵌套的子图
gs_nested = gs[0, 1].subgridspec(2, 2)
ax2_1 = fig.add_subplot(gs_nested[0, 0])
ax2_2 = fig.add_subplot(gs_nested[0, 1])
ax2_3 = fig.add_subplot(gs_nested[1, 0])
ax2_4 = fig.add_subplot(gs_nested[1, 1])
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title('Sine Wave - how2matplotlib.com')
ax3.plot(x, np.cos(x))
ax3.set_title('Cosine Wave - how2matplotlib.com')
for ax in [ax2_1, ax2_2, ax2_3, ax2_4]:
ax.plot(x, np.random.rand(100))
ax.set_title('Random Data - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何创建一个复杂的嵌套子图布局。我们首先创建了一个2×2的主布局,然后在右上角的子图中嵌套了一个2×2的子布局。
8. 使用constrained_layout
constrained_layout是一个新的自动布局机制,可以自动调整子图的大小和位置,以避免重叠和不一致的间距:
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(10, 8), constrained_layout=True)
x = np.linspace(0, 10, 100)
for i in range(2):
for j in range(2):
axs[i, j].plot(x, np.sin(x + i + j))
axs[i, j].set_title(f'Sine Wave {i+1},{j+1} - how2matplotlib.com')
axs[i, j].set_xlabel('X axis')
axs[i, j].set_ylabel('Y axis')
plt.show()
Output:
在这个例子中,我们使用constrained_layout=True来自动调整子图布局,这样可以确保所有的标签和标题都能完整显示,而不会相互重叠。
9. 创建3D子图plt.subplots不仅可以创建2D子图,还可以创建3D子图:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig, axs = plt.subplots(2, 2, figsize=(12, 10), subplot_kw={'projection': '3d'})
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
for i in range(2):
for j in range(2):
Z = np.sin(np.sqrt(X**2 + Y**2) + i + j)
axs[i, j].plot_surface(X, Y, Z, cmap='viridis')
axs[i, j].set_title(f'3D Surface {i+1},{j+1} - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了四个3D子图,每个子图都显示了一个稍微不同的3D表面。
10. 使用不同的投影
plt.subplots还允许我们在同一个图形中使用不同的投影:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(12, 10))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='polar')
ax3 = fig.add_subplot(223, projection='3d')
ax4 = fig.add_subplot(224)
# 2D plot
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title('2D Plot - how2matplotlib.com')
# Polar plot
theta = np.linspace(0, 2*np.pi, 100)
r = np.cos(4*theta)
ax2.plot(theta, r)
ax2.set_title('Polar Plot - how2matplotlib.com')
# 3D plot
X, Y = np.meshgrid(x, x)
Z = np.sin(np.sqrt(X**2 + Y**2))
ax3.plot_surface(X, Y, Z, cmap='viridis')
ax3.set_title('3D Plot - how2matplotlib.com')
# Image plot
img = np.random.rand(10, 10)
ax4.imshow(img, cmap='gray')
ax4.set_title('Image Plot - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何在一个图形中创建四个不同类型的子图:一个普通的2D图,一个极坐标图,一个3D图,和一个图像显示。
11. 创建非矩形布局
虽然plt.subplots通常用于创建矩形网格布局,但我们也可以使用它来创建更复杂的非矩形布局:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 8))
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax2 = fig.add_subplot(gs[1, :-1])
ax3 = fig.add_subplot(gs[1:, -1])
ax4 = fig.add_subplot(gs[-1, 0])
ax5 = fig.add_subplot(gs[-1, -2])
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title('Sine Wave - how2matplotlib.com')
ax2.plot(x, np.cos(x))
ax2.set_title('Cosine Wave - how2matplotlib.com')
ax3.plot(x, np.tan(x))
ax3.set_title('Tangent Wave - how2matplotlib.com')
ax4.plot(x, np.exp(x))
ax4.set_title('Exponential Function - how2matplotlib.com')
ax5.plot(x, np.log(x))
ax5.set_title('Logarithmic Function - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个非矩形的布局,包括一个跨越整个顶部的子图,一个占据中间两列的子图,一个占据右侧两行的子图,以及底部的两个小子图。
12. 使用add_subplot方法
除了使用plt.subplots,我们还可以使用Figure对象的add_subplot方法来逐个添加子图:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 8))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title('Sine Wave - how2matplotlib.com')
ax2.plot(x, np.cos(x))
ax2.set_title('Cosine Wave - how2matplotlib.com')
ax3.plot(x, np.exp(x))
ax3.set_title('Exponential Function - how2matplotlib.com')
ax4.plot(x, np.log(x))
ax4.set_title('Logarithmic Function - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个方法给了我们更多的灵活性,因为我们可以在任何时候添加新的子图,而不需要预先知道子图的总数。
13. 使用subplot2grid
subplot2grid是另一个用于创建复杂布局的有用工具:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 8))
ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3)
ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
ax4 = plt.subplot2grid((3, 3), (2, 0))
ax5 = plt.subplot2grid((3, 3), (2, 1))
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title('Sine Wave - how2matplotlib.com')
ax2.plot(x, np.cos(x))
ax2.set_title('Cosine Wave - how2matplotlib.com')
ax3.plot(x, np.tan(x))
ax3.set_title('Tangent Wave - how2matplotlib.com')
ax4.plot(x, np.exp(x))
ax4.set_title('Exponential Function - how2matplotlib.com')
ax5.plot(x, np.log(x))
ax5.set_title('Logarithmic Function - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
subplot2grid允许我们指定每个子图的起始位置、跨度和大小,从而创建非常灵活的布局。
14. 创建具有不同比例的子图
有时我们可能需要在同一个图形中显示具有不同比例的数据:
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = 1000 * np.sin(x)
ax1.plot(x, y1)
ax1.set_title('Small Scale Sine Wave - how2matplotlib.com')
ax2.plot(x, y2)
ax2.set_title('Large Scale Sine Wave - how2matplotlib.com')
# 设置不同的y轴范围
ax1.set_ylim(-1.5, 1.5)
ax2.set_ylim(-1500, 1500)
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了两个子图,一个显示小尺度的正弦波,另一个显示大尺度的正弦波。通过设置不同的y轴范围,我们可以在同一个图形中清晰地显示这两种不同尺度的数据。
15. 创建具有共享colorbar的子图
当我们有多个相关的图像或热图时,使用共享的colorbar可以使比较更加直观:
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 创建两个相关但不同的数据集
data1 = np.random.rand(10, 10)
data2 = data1 + 0.1 * np.random.rand(10, 10)
# 绘制两个热图
im1 = ax1.imshow(data1, cmap='viridis')
im2 = ax2.imshow(data2, cmap='viridis')
ax1.set_title('Dataset 1 - how2matplotlib.com')
ax2.set_title('Dataset 2 - how2matplotlib.com')
# 添加共享的colorbar
fig.colorbar(im1, ax=[ax1, ax2], label='Value')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了两个相关的数据集,并在两个子图中分别显示它们。通过添加一个共享的colorbar,我们可以直观地比较这两个数据集。
结论
plt.subplots是Matplotlib库中一个非常强大和灵活的工具,它允许我们创建各种复杂的图形布局。从简单的网格布局到复杂的嵌套布局,从2D图到3D图,从单一类型的图到混合不同类型的图,plt.subplots都能轻松应对。
通过本文的详细介绍和丰富的示例,我们探索了plt.subplots的多种用法和技巧。这些知识将帮助你更好地组织和展示你的数据,创建更加专业和吸引人的可视化效果。
记住,数据可视化不仅仅是展示数据,更是讲述数据背后的故事。通过灵活运用plt.subplots,你可以更有效地传达数据中的洞察和发现,让你的可视化作品更具说服力和影响力。
无论你是数据科学家、研究人员,还是任何需要进行数据可视化的专业人士,掌握plt.subplots都将极大地提升你的数据展示能力。继续探索和实践,你会发现Matplotlib和plt.subplots还有更多令人惊喜的功能等待你去发掘!