Matplotlib 图形大小和子图布局:全面指南
参考:matplotlib figure size subplots
Matplotlib 是 Python 中最流行的数据可视化库之一,它提供了强大而灵活的工具来创建各种类型的图表和绘图。在使用 Matplotlib 时,了解如何控制图形大小和创建子图布局是非常重要的。本文将深入探讨 Matplotlib 中的 figure size 和 subplots 概念,帮助你更好地掌握这些关键技术。
1. 图形大小(Figure Size)
在 Matplotlib 中,图形大小指的是整个图形(Figure)的尺寸。控制图形大小对于创建美观、易读的可视化效果至关重要。
1.1 设置图形大小
最常用的设置图形大小的方法是使用 plt.figure()
函数的 figsize
参数。这个参数接受一个元组,表示宽度和高度(以英寸为单位)。
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot([1, 2, 3, 4], [1, 4, 2, 3])
plt.title("How2matplotlib.com - Figure Size Example")
plt.show()
Output:
在这个例子中,我们创建了一个宽 10 英寸、高 6 英寸的图形。figsize=(10, 6)
参数设置了图形的大小。
1.2 动态调整图形大小
有时,我们可能需要根据数据或其他条件动态调整图形大小。以下是一个示例:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randn(100, 5)
num_columns = data.shape[1]
# 动态设置图形大小
fig_width = 2 * num_columns # 每列 2 英寸宽
fig_height = 6 # 固定高度为 6 英寸
plt.figure(figsize=(fig_width, fig_height))
plt.boxplot(data)
plt.title("How2matplotlib.com - Dynamic Figure Size")
plt.show()
Output:
这个例子中,我们根据数据的列数动态设置图形的宽度,使每个箱线图有足够的空间显示。
1.3 保存特定大小的图形
当保存图形时,我们也可以指定输出文件的大小:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.figure(figsize=(8, 4))
plt.plot(x, y)
plt.title("How2matplotlib.com - Saving Specific Size")
plt.savefig('sine_wave.png', dpi=300, bbox_inches='tight')
plt.close()
这里,我们创建了一个 8×4 英寸的图形,并以 300 DPI 的分辨率保存为 PNG 文件。bbox_inches='tight'
参数确保图形被紧密裁剪,不留多余的空白。
2. 子图(Subplots)
子图允许在一个图形中创建多个相关的图表。这对于比较不同数据集或展示数据的不同方面非常有用。
2.1 创建基本子图
最简单的创建子图的方法是使用 plt.subplot()
函数:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
plt.figure(figsize=(12, 4))
plt.subplot(131)
plt.plot(x, np.sin(x))
plt.title("How2matplotlib.com - Sin")
plt.subplot(132)
plt.plot(x, np.cos(x))
plt.title("How2matplotlib.com - Cos")
plt.subplot(133)
plt.plot(x, np.tan(x))
plt.title("How2matplotlib.com - Tan")
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个包含三个子图的图形,分别显示正弦、余弦和正切函数。plt.subplot(131)
表示创建一个 1 行 3 列的子图布局,并选择第一个子图。
2.2 使用 plt.subplots() 函数
plt.subplots()
函数提供了一种更方便的方式来创建子图网格:
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(10, 8))
x = np.linspace(0, 5, 100)
axs[0, 0].plot(x, x)
axs[0, 0].set_title("How2matplotlib.com - Linear")
axs[0, 1].plot(x, x**2)
axs[0, 1].set_title("How2matplotlib.com - Quadratic")
axs[1, 0].plot(x, np.sqrt(x))
axs[1, 0].set_title("How2matplotlib.com - Square Root")
axs[1, 1].plot(x, np.exp(x))
axs[1, 1].set_title("How2matplotlib.com - Exponential")
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个 2×2 的子图网格,每个子图显示不同的数学函数。
2.3 不规则子图布局
有时,我们可能需要创建不规则的子图布局。gridspec
模块提供了更灵活的布局选项:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
fig = plt.figure(figsize=(12, 8))
gs = gridspec.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, 5, 100)
ax1.plot(x, np.sin(x))
ax1.set_title("How2matplotlib.com - Sine Wave")
ax2.plot(x, np.cos(x))
ax2.set_title("How2matplotlib.com - Cosine Wave")
ax3.plot(x, np.tan(x))
ax3.set_title("How2matplotlib.com - Tangent")
ax4.plot(x, x**2)
ax4.set_title("How2matplotlib.com - Quadratic")
ax5.plot(x, np.sqrt(x))
ax5.set_title("How2matplotlib.com - Square Root")
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何创建一个复杂的不规则子图布局,其中子图的大小和位置各不相同。
2.4 共享轴
在某些情况下,我们可能希望子图之间共享 x 轴或 y 轴:
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
ax1.plot(x, y1)
ax1.set_title("How2matplotlib.com - Sine Wave")
ax2.plot(x, y2)
ax2.set_title("How2matplotlib.com - Cosine Wave")
plt.tight_layout()
plt.show()
Output:
在这个例子中,两个子图共享相同的 x 轴,这在比较具有相同 x 范围的不同数据集时非常有用。
2.5 子图中的子图
Matplotlib 还允许在子图内创建更小的子图:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111)
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax.plot(x, y)
ax.set_title("How2matplotlib.com - Main Plot")
# 创建子图中的子图
inset_ax = ax.inset_axes([0.6, 0.1, 0.3, 0.3])
inset_ax.plot(x, y)
inset_ax.set_title("Inset", fontsize=8)
inset_ax.set_xlim(4, 6)
inset_ax.set_ylim(-1, 1)
ax.indicate_inset_zoom(inset_ax)
plt.show()
Output:
这个例子在主图中创建了一个小的插入图,用于放大显示主图的某个部分。
3. 组合图形大小和子图技术
现在,让我们看看如何结合图形大小和子图技术来创建更复杂的可视化:
3.1 多行多列的子图布局
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(3, 3, figsize=(15, 15))
x = np.linspace(0, 10, 100)
for i in range(3):
for j in range(3):
axs[i, j].plot(x, np.sin(x + i*j))
axs[i, j].set_title(f"How2matplotlib.com - Plot {i+1},{j+1}")
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个 3×3 的子图网格,每个子图显示稍微不同的正弦波。
3.2 不同大小的子图
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
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])
ax2 = fig.add_subplot(gs[0, 1])
ax3 = fig.add_subplot(gs[1, :])
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x))
ax1.set_title("How2matplotlib.com - Sine")
ax2.plot(x, np.cos(x))
ax2.set_title("How2matplotlib.com - Cosine")
ax3.plot(x, np.tan(x))
ax3.set_title("How2matplotlib.com - Tangent")
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何创建具有不同大小的子图,使用 GridSpec
来精确控制每个子图的大小和位置。
3.3 子图中的多个图表
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
x = np.linspace(0, 10, 100)
axs[0, 0].plot(x, np.sin(x), 'r', label='sin(x)')
axs[0, 0].plot(x, np.cos(x), 'b', label='cos(x)')
axs[0, 0].set_title("How2matplotlib.com - Trigonometric Functions")
axs[0, 0].legend()
axs[0, 1].scatter(np.random.rand(50), np.random.rand(50))
axs[0, 1].set_title("How2matplotlib.com - Scatter Plot")
axs[1, 0].bar(['A', 'B', 'C', 'D'], [3, 7, 2, 5])
axs[1, 0].set_title("How2matplotlib.com - Bar Chart")
axs[1, 1].hist(np.random.randn(1000))
axs[1, 1].set_title("How2matplotlib.com - Histogram")
plt.tight_layout()
plt.show()
Output:
这个例子在一个图形中展示了四种不同类型的图表,每个都在自己的子图中。
3.4 子图标题和总标题
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
fig.suptitle("How2matplotlib.com - Various Mathematical Functions", fontsize=16)
x = np.linspace(0, 10, 100)
axs[0, 0].plot(x, np.sin(x))
axs[0, 0].set_title("Sine Function")
axs[0, 1].plot(x, np.cos(x))
axs[0, 1].set_title("Cosine Function")
axs[1, 0].plot(x, np.exp(x))
axs[1, 0].set_title("Exponential Function")
axs[1, 1].plot(x, np.log(x))
axs[1, 1].set_title("Logarithmic Function")
plt.tight_layout()
plt.subplots_adjust(top=0.92)
plt.show()
Output:
这个例子展示了如何为整个图形添加一个总标题,同时为每个子图设置单独的标题。
3.5 调整子图间距
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"How2matplotlib.com - Plot {i+1},{j+1}")
plt.tight_layout()
plt.subplots_adjust(wspace=0.3, hspace=0.3)
plt.show()
Output:
这个例子展示了如何使用 subplots_adjust
函数来调整子图之间的间距。
4. 高级技巧和注意事项
4.1 自适应布局
Matplotlib 提供了自适应布局功能,可以自动调整子图大小和间距:
“`python“`python
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”How2matplotlib.com – Plot {i+1},{j+1}”)
axs[i, j].set_xlabel(“X axis”)
axs[i, j].set_ylabel(“Y axis”)
plt.tight_layout()
plt.show()
Output:
![Matplotlib 图形大小和子图布局:全面指南](https://static.deepinout.com/geekdocs/2024/11/16/20240825221744-13.png "Matplotlib 图形大小和子图布局:全面指南")
这个例子使用 `tight_layout()` 函数自动调整子图布局,以避免重叠和确保标签可见。
### 4.2 处理长标题和标签
当处理长标题或标签时,可能需要调整布局以确保所有文本都可见:
```python
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"How2matplotlib.com - Very Long Title for Plot {i+1},{j+1}")
axs[i, j].set_xlabel("This is a very long X axis label")
axs[i, j].set_ylabel("This is a very long Y axis label")
plt.tight_layout()
plt.subplots_adjust(top=0.9, bottom=0.1, left=0.1, right=0.9)
plt.show()
Output:
这个例子展示了如何处理长标题和标签,通过调整子图间距来确保所有文本都清晰可见。
4.3 在子图中使用不同的比例
有时,我们可能需要在同一图形中使用不同的比例:
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 = np.exp(x)
ax1.plot(x, y1)
ax1.set_title("How2matplotlib.com - Sine Function")
ax1.set_ylim(-1.5, 1.5)
ax2.plot(x, y2)
ax2.set_title("How2matplotlib.com - Exponential Function")
ax2.set_yscale('log')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何在一个子图中使用线性比例,在另一个子图中使用对数比例。
4.4 子图中的图例位置
当处理多个子图时,正确放置图例很重要:
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), label='sin')
axs[i, j].plot(x, np.cos(x), label='cos')
axs[i, j].set_title(f"How2matplotlib.com - Plot {i+1},{j+1}")
axs[i, j].legend(loc='upper right')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何在每个子图中放置图例,并使用 loc
参数指定位置。
4.5 子图中的颜色条
在某些可视化中,添加颜色条(colorbar)可能很有用:
import matplotlib.pyplot as plt
import numpy as np
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
for i in range(2):
for j in range(2):
data = np.random.rand(10, 10)
im = axs[i, j].imshow(data, cmap='viridis')
axs[i, j].set_title(f"How2matplotlib.com - Plot {i+1},{j+1}")
fig.colorbar(im, ax=axs[i, j])
plt.tight_layout()
plt.show()
Output:
这个例子在每个子图中添加了一个颜色条,用于解释热图的颜色含义。
5. 实际应用示例
让我们看一些更复杂的实际应用示例,展示如何结合使用图形大小和子图布局来创建信息丰富的可视化。
5.1 股票价格分析
import matplotlib.pyplot as plt
import numpy as np
# 模拟股票数据
dates = np.arange('2023-01-01', '2023-12-31', dtype='datetime64[D]')
price = 100 + np.cumsum(np.random.randn(len(dates)) * 2)
volume = np.random.randint(1000, 10000, size=len(dates))
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})
ax1.plot(dates, price)
ax1.set_title("How2matplotlib.com - Stock Price Analysis")
ax1.set_ylabel("Price ($)")
ax2.bar(dates, volume, width=1)
ax2.set_ylabel("Volume")
ax2.set_xlabel("Date")
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个股票价格和交易量的分析图,使用共享 x 轴的两个子图。
5.2 天气数据可视化
import matplotlib.pyplot as plt
import numpy as np
# 模拟天气数据
dates = np.arange('2023-01-01', '2023-12-31', dtype='datetime64[D]')
temp_high = 20 + 15 * np.sin(np.arange(len(dates)) * 2 * np.pi / 365) + np.random.randn(len(dates)) * 3
temp_low = temp_high - 10 + np.random.randn(len(dates)) * 2
rainfall = np.random.exponential(5, size=len(dates))
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), sharex=True)
ax1.plot(dates, temp_high, label='High')
ax1.plot(dates, temp_low, label='Low')
ax1.set_title("How2matplotlib.com - Temperature and Rainfall")
ax1.set_ylabel("Temperature (°C)")
ax1.legend()
ax2.bar(dates, rainfall, width=1, alpha=0.5)
ax2.set_ylabel("Rainfall (mm)")
ax2.set_xlabel("Date")
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个年度天气数据可视化,包括温度和降雨量。
5.3 多变量数据分析
import matplotlib.pyplot as plt
import numpy as np
# 生成多变量数据
n = 1000
x = np.random.randn(n)
y = 2*x + np.random.randn(n)
z = x - y + np.random.randn(n)
fig = plt.figure(figsize=(12, 10))
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, :])
ax1.scatter(x, y)
ax1.set_title("How2matplotlib.com - X vs Y")
ax1.set_xlabel("X")
ax1.set_ylabel("Y")
ax2.scatter(x, z)
ax2.set_title("How2matplotlib.com - X vs Z")
ax2.set_xlabel("X")
ax2.set_ylabel("Z")
ax3.scatter(y, z, c=x, cmap='viridis')
ax3.set_title("How2matplotlib.com - Y vs Z (color: X)")
ax3.set_xlabel("Y")
ax3.set_ylabel("Z")
plt.colorbar(ax3.collections[0], ax=ax3, label="X value")
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何使用不同大小的子图来分析多变量数据,包括散点图和颜色编码。
6. 总结
通过本文,我们深入探讨了 Matplotlib 中图形大小和子图布局的各个方面。我们学习了如何:
- 控制整体图形大小
- 创建和自定义子图布局
- 处理不规则子图布局
- 调整子图间距和对齐
- 在复杂的可视化中结合使用这些技术
掌握这些技能将使你能够创建更专业、更有洞察力的数据可视化。记住,好的可视化不仅仅是展示数据,还要讲述数据背后的故事。通过适当地设置图形大小和子图布局,你可以确保你的可视化清晰、引人注目,并有效地传达你想要表达的信息。
在实际应用中,始终考虑你的目标受众和展示环境。例如,用于演示的图表可能需要更大的字体和更简单的布局,而用于科学论文的图表可能需要更详细的信息和更紧凑的布局。
最后,不要忘记实践的重要性。尝试不同的布局和大小设置,看看它们如何影响你的可视化效果。随着经验的积累,你将能够更直观地选择最适合你数据的图形大小和子图布局。