Matplotlib中如何向图形添加坐标轴:全面指南
参考:How to Add Axes to a Figure in Matplotlib
Matplotlib是Python中最流行的数据可视化库之一,它提供了丰富的功能来创建各种类型的图表和绘图。在使用Matplotlib时,了解如何向图形添加坐标轴是非常重要的,因为这可以让我们更灵活地控制图表的布局和展示多个相关的数据集。本文将详细介绍在Matplotlib中添加坐标轴的各种方法和技巧,帮助你更好地掌握这一重要技能。
1. 基本概念:Figure和Axes
在深入探讨如何添加坐标轴之前,我们需要先了解Matplotlib中的两个核心概念:Figure和Axes。
- Figure(图形):是整个图表的容器,可以包含一个或多个Axes对象。
- Axes(坐标轴):是实际的绘图区域,包含了数据、坐标轴、标题等元素。
理解这两个概念对于掌握如何添加和操作坐标轴至关重要。
让我们从一个简单的例子开始:
import matplotlib.pyplot as plt
# 创建一个Figure对象
fig = plt.figure(figsize=(8, 6))
# 在Figure中添加一个Axes对象
ax = fig.add_subplot(111)
# 在Axes上绘制一些数据
ax.plot([1, 2, 3, 4], [1, 4, 2, 3], label='Data from how2matplotlib.com')
# 添加标题和标签
ax.set_title('Simple Plot')
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
ax.legend()
plt.show()
Output:
在这个例子中,我们首先创建了一个Figure对象,然后使用add_subplot()
方法添加了一个Axes对象。接着,我们在这个Axes上绘制了一条简单的线,并添加了标题和标签。
2. 使用plt.subplots()创建多个子图
plt.subplots()
是一个非常方便的函数,它可以一次性创建Figure和Axes对象。这个函数特别适合用于创建包含多个子图的图形。
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)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.exp(-x/10)
y4 = np.log(x + 1)
# 在每个子图上绘制不同的数据
axs[0, 0].plot(x, y1, label='Sin(x)')
axs[0, 1].plot(x, y2, label='Cos(x)')
axs[1, 0].plot(x, y3, label='Exp(-x/10)')
axs[1, 1].plot(x, y4, label='Log(x+1)')
# 为每个子图添加标题和图例
for i in range(2):
for j in range(2):
axs[i, j].set_title(f'Subplot {i+1},{j+1} from how2matplotlib.com')
axs[i, j].legend()
# 调整子图之间的间距
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们使用plt.subplots(2, 2)
创建了一个2×2的子图布局。返回的axs
是一个2×2的NumPy数组,其中每个元素都是一个Axes对象。我们可以通过索引来访问每个子图,并在其上绘制不同的数据。
3. 使用add_axes()精确控制坐标轴位置
有时候,我们需要更精确地控制坐标轴在Figure中的位置。这时可以使用add_axes()
方法,它允许我们指定坐标轴的确切位置和大小。
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(10, 8))
# 主坐标轴
ax_main = fig.add_axes([0.1, 0.1, 0.8, 0.8])
x = np.linspace(0, 10, 100)
ax_main.plot(x, np.sin(x), label='Sin(x) from how2matplotlib.com')
ax_main.set_title('Main Plot')
ax_main.legend()
# 右上角的小坐标轴
ax_top_right = fig.add_axes([0.65, 0.65, 0.25, 0.25])
ax_top_right.plot(x, np.cos(x), 'r-', label='Cos(x)')
ax_top_right.set_title('Top Right')
ax_top_right.legend()
# 左下角的小坐标轴
ax_bottom_left = fig.add_axes([0.2, 0.2, 0.25, 0.25])
ax_bottom_left.plot(x, np.exp(-x/10), 'g-', label='Exp(-x/10)')
ax_bottom_left.set_title('Bottom Left')
ax_bottom_left.legend()
plt.show()
Output:
在这个例子中,我们使用add_axes()
方法添加了三个坐标轴。每个add_axes()
调用的参数是一个列表[left, bottom, width, height]
,这些值都是相对于整个Figure的比例。例如,[0.1, 0.1, 0.8, 0.8]
表示坐标轴的左下角位于Figure的(10%, 10%)位置,宽度为Figure宽度的80%,高度为Figure高度的80%。
4. 使用GridSpec创建复杂的子图布局
对于更复杂的子图布局,Matplotlib提供了GridSpec类。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, 10, 100)
# 在每个子图上绘制不同的数据
ax1.plot(x, np.sin(x), label='Sin(x) from how2matplotlib.com')
ax2.plot(x, np.cos(x), label='Cos(x) from how2matplotlib.com')
ax3.plot(x, np.tan(x), label='Tan(x) from how2matplotlib.com')
ax4.plot(x, np.exp(x), label='Exp(x) from how2matplotlib.com')
ax5.plot(x, np.log(x), label='Log(x) from how2matplotlib.com')
# 为每个子图添加标题和图例
for ax in [ax1, ax2, ax3, ax4, ax5]:
ax.set_title(f'Subplot {ax.get_geometry()}')
ax.legend()
plt.tight_layout()
plt.show()
在这个例子中,我们使用GridSpec创建了一个3×3的网格,然后通过不同的索引组合创建了5个子图,其中一些子图跨越了多个网格单元。这种方法可以创建非常灵活的布局,适合展示复杂的数据关系。
5. 在已有的Axes上添加新的坐标轴
有时候,我们可能需要在同一个绘图区域显示不同尺度的数据。这时,我们可以使用twinx()
或twiny()
方法在已有的Axes上添加一个共享x轴或y轴的新坐标轴。
import matplotlib.pyplot as plt
import numpy as np
fig, ax1 = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.exp(x/10)
# 绘制第一个数据集
color = 'tab:blue'
ax1.set_xlabel('X-axis')
ax1.set_ylabel('Sin(x)', color=color)
ax1.plot(x, y1, color=color, label='Sin(x) from how2matplotlib.com')
ax1.tick_params(axis='y', labelcolor=color)
# 创建一个共享x轴的新坐标轴
ax2 = ax1.twinx()
color = 'tab:orange'
ax2.set_ylabel('Exp(x/10)', color=color)
ax2.plot(x, y2, color=color, label='Exp(x/10) from how2matplotlib.com')
ax2.tick_params(axis='y', labelcolor=color)
# 添加标题
fig.suptitle('Two scales: Sin(x) and Exp(x/10)')
# 添加图例
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
plt.show()
Output:
在这个例子中,我们首先创建了一个普通的Axes对象ax1
,然后使用twinx()
方法创建了一个共享x轴的新坐标轴ax2
。这样,我们就可以在同一个图表中显示两个不同尺度的y轴数据。
6. 使用inset_axes()添加嵌入式坐标轴
有时候,我们可能想在主图中添加一个小的嵌入式图表,用于显示数据的某个特定部分或相关的补充信息。这可以通过inset_axes()
方法实现。
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
fig, ax = plt.subplots(figsize=(10, 6))
# 生成主图的数据
x = np.linspace(0, 10, 1000)
y = np.sin(x) * np.exp(-x/10)
# 绘制主图
ax.plot(x, y, label='Main data from how2matplotlib.com')
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
ax.set_title('Main Plot with Inset')
ax.legend()
# 创建嵌入式坐标轴
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.5)
axins.set_title('Zoomed section')
# 在主图上标记放大区域
ax.indicate_inset_zoom(axins, edgecolor="black")
plt.show()
Output:
在这个例子中,我们首先创建了一个主图,然后使用inset_axes()
方法在主图中添加了一个小的嵌入式坐标轴。这个嵌入式坐标轴显示了主图数据的一个放大部分。我们还使用indicate_inset_zoom()
方法在主图上标记了放大区域。
7. 创建极坐标图
除了常见的笛卡尔坐标系,Matplotlib还支持其他类型的坐标系,如极坐标系。我们可以使用projection='polar'
参数来创建极坐标图。
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 6))
# 创建笛卡尔坐标系的子图
ax1 = fig.add_subplot(121)
theta = np.linspace(0, 2*np.pi, 100)
r = np.cos(4*theta)
ax1.plot(theta, r)
ax1.set_title('Cartesian Plot')
ax1.set_xlabel('Theta')
ax1.set_ylabel('R')
# 创建极坐标系的子图
ax2 = fig.add_subplot(122, projection='polar')
ax2.plot(theta, r)
ax2.set_title('Polar Plot from how2matplotlib.com')
ax2.set_rticks([0.5, 1]) # 设置径向刻度
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了两个子图:一个使用笛卡尔坐标系,另一个使用极坐标系。两个图表显示的是同一组数据,但由于坐标系的不同,呈现出完全不同的视觉效果。
8. 3D图表中的多个坐标轴
Matplotlib还支持创建3D图表。在3D图表中,我们可以添加多个平面来展示不同的数据投影。
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
# 生成数据
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
## 绘制3D表面
surf = ax.plot_surface(X, Y, Z, cmap='viridis')
# 添加颜色条
fig.colorbar(surf, shrink=0.5, aspect=5)
# 在XZ平面上添加等高线图
ax.contour(X, Y, Z, zdir='y', offset=5, cmap='viridis')
# 在YZ平面上添加等高线图
ax.contour(X, Y, Z, zdir='x', offset=-5, cmap='viridis')
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
ax.set_zlabel('Z-axis')
ax.set_title('3D Surface with Projections from how2matplotlib.com')
plt.show()
Output:
在这个例子中,我们创建了一个3D表面图,并在XZ和YZ平面上添加了等高线图作为投影。这种方法可以帮助我们从不同角度理解3D数据的分布。
9. 使用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=2)
ax2 = plt.subplot2grid((3, 3), (0, 2), rowspan=3)
ax3 = plt.subplot2grid((3, 3), (1, 0), rowspan=2, colspan=2)
# 生成一些数据
x = np.linspace(0, 10, 100)
# 在每个子图上绘制不同的数据
ax1.plot(x, np.sin(x), label='Sin(x) from how2matplotlib.com')
ax2.plot(x, np.cos(x), label='Cos(x) from how2matplotlib.com')
ax3.plot(x, np.tan(x), label='Tan(x) from how2matplotlib.com')
# 为每个子图添加标题和图例
ax1.set_title('Subplot 1')
ax2.set_title('Subplot 2')
ax3.set_title('Subplot 3')
for ax in [ax1, ax2, ax3]:
ax.legend()
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们使用subplot2grid()
创建了三个不同大小和位置的子图。这种方法特别适合创建复杂的、非对称的图表布局。
10. 使用constrained_layout自动调整子图布局
当我们有多个子图时,确保它们之间不重叠并且标签不被截断是很重要的。Matplotlib的constrained_layout
功能可以自动调整子图的大小和位置,以避免这些问题。
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['figure.constrained_layout.use'] = True
fig, axs = plt.subplots(2, 2, figsize=(10, 8))
fig.suptitle('Constrained Layout Example from how2matplotlib.com', fontsize=16)
# 生成一些数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.exp(-x/10)
y4 = np.log(x + 1)
# 在每个子图上绘制不同的数据
axs[0, 0].plot(x, y1)
axs[0, 0].set_title('Sin(x)')
axs[0, 1].plot(x, y2)
axs[0, 1].set_title('Cos(x)')
axs[1, 0].plot(x, y3)
axs[1, 0].set_title('Exp(-x/10)')
axs[1, 1].plot(x, y4)
axs[1, 1].set_title('Log(x+1)')
# 为每个子图添加x和y标签
for ax in axs.flat:
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
plt.show()
Output:
在这个例子中,我们通过设置plt.rcParams['figure.constrained_layout.use'] = True
启用了constrained_layout
。这样,Matplotlib会自动调整子图的布局,确保标题和标签不会重叠或被截断。
11. 创建共享坐标轴的子图
有时,我们可能想创建共享x轴或y轴的子图。这可以通过sharex
和sharey
参数来实现。
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(10, 12), sharex=True)
fig.suptitle('Subplots with Shared X-axis from how2matplotlib.com', fontsize=16)
# 生成数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.tan(x)
# 在每个子图上绘制不同的数据
ax1.plot(x, y1, label='Sin(x)')
ax2.plot(x, y2, label='Cos(x)')
ax3.plot(x, y3, label='Tan(x)')
# 设置标题和标签
ax1.set_title('Sin(x)')
ax2.set_title('Cos(x)')
ax3.set_title('Tan(x)')
ax3.set_xlabel('X-axis')
ax1.set_ylabel('Y-axis')
ax2.set_ylabel('Y-axis')
ax3.set_ylabel('Y-axis')
# 添加图例
for ax in [ax1, ax2, ax3]:
ax.legend()
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了三个垂直排列的子图,它们共享同一个x轴。这种布局特别适合比较具有相同x轴范围但不同y轴范围的多个数据集。
12. 使用axisartist创建自定义坐标轴
Matplotlib的axisartist
工具包提供了一种创建自定义坐标轴的方法,允许我们更灵活地控制坐标轴的外观和行为。
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axisartist import SubplotHost
fig = plt.figure(figsize=(10, 8))
ax = SubplotHost(fig, 111)
fig.add_subplot(ax)
# 创建平行于y轴的新坐标轴
ax.axis["right"] = ax.new_fixed_axis(loc="right", offset=(40, 0))
# 隐藏顶部和右侧的默认坐标轴
ax.axis["top"].set_visible(False)
ax.axis["right"].set_visible(False)
# 生成数据
x = np.linspace(-5, 5, 100)
y = x**2
# 绘制数据
ax.plot(x, y, label='y = x^2 from how2matplotlib.com')
# 设置标题和标签
ax.set_title('Custom Axis Example')
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
# 添加图例
ax.legend()
plt.show()
Output:
在这个例子中,我们使用SubplotHost
创建了一个自定义的坐标轴系统。我们添加了一个平行于y轴的新坐标轴,并隐藏了默认的顶部和右侧坐标轴。这种方法可以用来创建非常独特和定制化的图表布局。
13. 创建带有次坐标轴的图表
有时,我们可能需要在主坐标轴旁边添加次坐标轴,以显示额外的信息或不同的刻度。
import matplotlib.pyplot as plt
import numpy as np
fig, ax1 = plt.subplots(figsize=(10, 6))
# 设置主坐标轴
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
ax1.plot(x, y1, 'b-', label='Sin(x) from how2matplotlib.com')
ax1.set_xlabel('X-axis')
ax1.set_ylabel('Sin(x)', color='b')
ax1.tick_params(axis='y', labelcolor='b')
# 创建次坐标轴
ax2 = ax1.twinx()
y2 = np.cos(x)
ax2.plot(x, y2, 'r-', label='Cos(x) from how2matplotlib.com')
ax2.set_ylabel('Cos(x)', color='r')
ax2.tick_params(axis='y', labelcolor='r')
# 添加标题
plt.title('Sin(x) and Cos(x) with Primary and Secondary Y-axes')
# 添加图例
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个主坐标轴和一个次坐标轴。主坐标轴显示sin(x)函数,次坐标轴显示cos(x)函数。这种方法允许我们在同一个图表中比较两个不同尺度的数据集。
14. 创建带有断开坐标轴的图表
有时,我们可能需要在坐标轴上创建一个断开,以便更好地显示数据的不同范围。
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.transforms import BlendedGenericTransform
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8), sharex=True)
fig.subplots_adjust(hspace=0.05) # 减小子图之间的间距
# 生成数据
x = np.linspace(0, 10, 100)
y1 = np.exp(x)
y2 = np.sin(x) + 10
# 绘制上半部分
ax1.plot(x, y1, label='Exp(x) from how2matplotlib.com')
ax1.set_ylim(1000, 25000)
ax1.set_title('Exponential Growth with Broken Y-axis')
# 绘制下半部分
ax2.plot(x, y2, label='Sin(x) + 10 from how2matplotlib.com')
ax2.set_ylim(9, 11)
# 隐藏上半部分的x轴标签
ax1.tick_params(labelbottom=False)
# 添加y轴标签
ax1.set_ylabel('Y-axis (upper)')
ax2.set_ylabel('Y-axis (lower)')
ax2.set_xlabel('X-axis')
# 添加断开标记
d = .015 # 断开标记的大小
kwargs = dict(transform=BlendedGenericTransform(fig.transFigure, ax1.transAxes),
color='k', clip_on=False)
ax1.plot((-d, +d), (-d, +d), **kwargs) # 左上
ax1.plot((1-d, 1+d), (-d, +d), **kwargs) # 右上
kwargs.update(transform=BlendedGenericTransform(fig.transFigure, ax2.transAxes))
ax2.plot((-d, +d), (1-d, 1+d), **kwargs) # 左下
ax2.plot((1-d, 1+d), (1-d, 1+d), **kwargs) # 右下
# 添加图例
ax1.legend()
ax2.legend()
plt.show()
Output:
在这个例子中,我们创建了两个子图,分别显示数据的不同范围。通过调整子图之间的间距和添加断开标记,我们创建了一个看起来像单个断开坐标轴的效果。这种技术对于同时显示大范围和小范围的数据非常有用。
15. 创建极坐标子图
我们可以在一个图形中同时包含笛卡尔坐标系和极坐标系的子图。
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 6))
# 创建笛卡尔坐标系的子图
ax1 = fig.add_subplot(121)
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax1.plot(x, y, label='Sin(x) from how2matplotlib.com')
ax1.set_title('Cartesian Plot')
ax1.set_xlabel('X-axis')
ax1.set_ylabel('Y-axis')
ax1.legend()
# 创建极坐标系的子图
ax2 = fig.add_subplot(122, projection='polar')
theta = np.linspace(0, 2*np.pi, 100)
r = np.abs(np.sin(2*theta) * np.cos(2*theta))
ax2.plot(theta, r, label='|sin(2θ)cos(2θ)| from how2matplotlib.com')
ax2.set_title('Polar Plot')
ax2.legend()
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们在同一个图形中创建了一个笛卡尔坐标系的子图和一个极坐标系的子图。这种方法允许我们在一个图形中展示不同类型的数据可视化。
结论
在Matplotlib中添加坐标轴是一项强大而灵活的技能,它可以帮助我们创建复杂的、信息丰富的可视化。通过本文介绍的各种方法,从基本的子图创建到高级的自定义坐标轴,我们可以根据数据的特性和展示需求选择最合适的方法。
记住,好的数据可视化不仅仅是展示数据,更重要的是要清晰地传达信息。通过合理地使用多个坐标轴,我们可以在一个图形中展示更多的数据关系,比较不同的数据集,或者突出显示数据的某些特定方面。
在实际应用中,选择合适的坐标轴布局和类型取决于多个因素:
- 数据的性质:例如,时间序列数据可能适合使用共享x轴的多个子图,而相关性数据可能更适合使用散点图矩阵。
-
展示的目的:是要比较不同数据集,还是要展示同一数据集的不同方面?
-
目标受众:专业人士可能更容易理解复杂的图表布局,而对于一般受众,可能需要更简单、直观的布局。
-
美观和可读性:确保图表不仅信息丰富,而且视觉上吸引人,易于理解。
以下是一些使用多坐标轴时的最佳实践:
- 保持简洁:虽然Matplotlib允许创建非常复杂的图表,但过于复杂的布局可能会让读者感到困惑。只有在真正需要时才使用多个坐标轴。
-
使用一致的颜色和样式:为相关的数据使用相同的颜色或样式,这有助于读者快速理解图表。
-
适当使用标签和标题:确保每个坐标轴都有清晰的标签,并为整个图表添加一个描述性的标题。
-
考虑使用图例:特别是当有多个数据集时,清晰的图例可以帮助读者理解每条线或每个点代表什么。
-
利用空间:使用
tight_layout()
或constrained_layout
来自动调整子图之间的间距,确保标签不会重叠。 -
适当的比例:当使用双y轴时,确保两个y轴的比例选择得当,不会误导读者。
-
交互性:考虑使用Matplotlib的交互式功能,允许用户放大、平移或切换不同的视图。
最后,熟练掌握Matplotlib中添加坐标轴的各种方法需要大量的实践。建议读者尝试本文中的所有示例,并根据自己的数据和需求进行调整。随着经验的积累,你将能够创建出既美观又富有洞察力的数据可视化。
16. 创建带有不同比例的双轴图
有时,我们需要在同一个图表中显示具有不同数量级的数据。这时,使用具有不同比例的双轴图可能会很有帮助。
import matplotlib.pyplot as plt
import numpy as np
fig, ax1 = plt.subplots(figsize=(10, 6))
# 生成数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.exp(x)
# 绘制第一个数据集
color = 'tab:blue'
ax1.set_xlabel('X-axis')
ax1.set_ylabel('Sin(x)', color=color)
ax1.plot(x, y1, color=color, label='Sin(x) from how2matplotlib.com')
ax1.tick_params(axis='y', labelcolor=color)
# 创建第二个y轴
ax2 = ax1.twinx()
color = 'tab:orange'
ax2.set_ylabel('Exp(x)', color=color)
ax2.plot(x, y2, color=color, label='Exp(x) from how2matplotlib.com')
ax2.tick_params(axis='y', labelcolor=color)
# 添加标题
plt.title('Sin(x) and Exp(x) on Different Scales')
# 添加图例
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们在左侧y轴上显示了sin(x)函数,在右侧y轴上显示了exp(x)函数。这允许我们在同一个图表中比较这两个函数,尽管它们的值范围差异很大。
17. 创建子图网格
当我们需要创建大量相关但独立的子图时,使用子图网格可能会很有用。
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 8))
gs = fig.add_gridspec(3, 3)
# 生成一些数据
x = np.linspace(0, 10, 100)
functions = [
np.sin, np.cos, np.tan,
np.exp, np.log, np.sqrt,
lambda x: x**2, lambda x: x**3, lambda x: 1/x
]
for i, func in enumerate(functions):
ax = fig.add_subplot(gs[i//3, i%3])
ax.plot(x, func(x))
ax.set_title(f'{func.__name__}(x) from how2matplotlib.com')
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个3×3的子图网格,每个子图显示一个不同的数学函数。这种方法非常适合比较多个相关的数据集或函数。
18. 创建嵌套的子图
有时,我们可能需要在一个大的子图内部创建更小的子图。这可以通过嵌套使用add_axes()
方法来实现。
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 8))
# 创建主坐标轴
ax_main = fig.add_axes([0.1, 0.1, 0.8, 0.8])
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax_main.plot(x, y)
ax_main.set_title('Main Plot with Nested Subplots from how2matplotlib.com')
# 创建嵌套的子图
ax_top_left = fig.add_axes([0.2, 0.65, 0.2, 0.2])
ax_top_left.plot(x, np.cos(x), 'r-')
ax_top_left.set_title('Top Left')
ax_top_right = fig.add_axes([0.7, 0.65, 0.2, 0.2])
ax_top_right.plot(x, np.exp(x), 'g-')
ax_top_right.set_title('Top Right')
ax_bottom_left = fig.add_axes([0.2, 0.25, 0.2, 0.2])
ax_bottom_left.plot(x, np.log(x+1), 'm-')
ax_bottom_left.set_title('Bottom Left')
ax_bottom_right = fig.add_axes([0.7, 0.25, 0.2, 0.2])
ax_bottom_right.plot(x, x**2, 'y-')
ax_bottom_right.set_title('Bottom Right')
plt.show()
Output:
在这个例子中,我们在一个大的主图内创建了四个小的子图。这种技术可以用来突出显示数据的某些特定部分或相关的补充信息。
19. 创建具有共享坐标轴的不规则布局
有时,我们可能需要创建一个不规则的子图布局,其中某些子图共享坐标轴。这可以通过组合使用GridSpec
和sharex
/sharey
参数来实现。
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)
# 生成数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.tan(x)
# 创建子图
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])
# 绘制数据
ax1.plot(x, y1, label='Sin(x) from how2matplotlib.com')
ax2.plot(x, y2, label='Cos(x) from how2matplotlib.com')
ax3.plot(y1, y2, label='Sin(x) vs Cos(x) from how2matplotlib.com')
ax4.plot(x, y3, label='Tan(x) from how2matplotlib.com')
ax5.plot(x, np.exp(x), label='Exp(x) from how2matplotlib.com')
# 设置标题和标签
ax1.set_title('Sin(x)')
ax2.set_title('Cos(x)')
ax3.set_title('Sin(x) vs Cos(x)')
ax4.set_title('Tan(x)')
ax5.set_title('Exp(x)')
# 添加图例
for ax in [ax1, ax2, ax3, ax4, ax5]:
ax.legend()
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个不规则的子图布局,其中一些子图跨越了多个网格单元。这种布局允许我们在一个图形中展示多个相关但不同的数据视图。
20. 创建带有颜色条的多子图
当我们需要在多个子图中使用相同的颜色映射时,创建一个共享的颜色条可能会很有用。
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 生成数据
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z1 = np.sin(X) * np.cos(Y)
Z2 = np.cos(X) * np.sin(Y)
# 创建颜色映射
cmap = plt.get_cmap('viridis')
# 绘制第一个子图
im1 = ax1.imshow(Z1, cmap=cmap, extent=[-3, 3, -3, 3], origin='lower', aspect='auto')
ax1.set_title('Sin(X) * Cos(Y) from how2matplotlib.com')
# 绘制第二个子图
im2 = ax2.imshow(Z2, cmap=cmap, extent=[-3, 3, -3, 3], origin='lower', aspect='auto')
ax2.set_title('Cos(X) * Sin(Y) from how2matplotlib.com')
# 添加颜色条
cbar = fig.colorbar(im1, ax=[ax1, ax2], orientation='horizontal', pad=0.1)
cbar.set_label('Value')
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了两个子图,每个子图显示一个不同的2D函数。我们使用相同的颜色映射来绘制这两个函数,并添加了一个共享的水平颜色条。这种方法使得比较两个子图变得更加容易。
通过这20个示例,我们展示了Matplotlib中添加和操作坐标轴的多种方法。这些技术可以帮助你创建复杂的、信息丰富的数据可视化,以满足各种不同的需求。记住,好的数据可视化不仅仅是展示数据,更重要的是要清晰地传达信息。选择合适的图表类型和布局,可以大大提高你的数据分析和展示的效果。