使用matplotlib进行3D图的标签处理

5 投票
2 回答
13852 浏览
提问于 2025-04-18 15:33

我写了以下代码,用来在python和matplotlib中生成一个图形:

fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(1,1,1, projection='3d')

ax.plot_surface(KX[kxl3d:kxr3d,kxl3d:kxr3d], KY[kxl3d:kxr3d,kxl3d:kxr3d],
                BLP[kxl3d:kxr3d,kxl3d:kxr3d], rstride=8, cstride=8, alpha=0.4)

for idx in range(3):
    ax.plot(kx[x_points]+momentum_spi[idx,0], ky[y_points]+momentum_spi[idx,1],
            energy_spi[idx], linestyle='none', marker='o', 
            markerfacecolor=color_spi[idx], markersize=5)

ax.set_xlim(kl3d, kr3d)
ax.set_ylim(kl3d, kr3d)

ax.set_xlabel(r'$k_x[\mu m^{-1}]$')
ax.set_ylabel(r'$k_y[\mu m^{-1}]$')
ax.set_zlabel(r'$\epsilon-\omega_X[\gamma_p]$')

生成的结果是:

3d_rings

我想问的是,如何才能:

  1. 把z轴的标签和刻度标签移动到图形的左边,这样它们就不会被环形图覆盖了;
  2. 增加x轴和y轴的刻度标签与轴标签之间的间距(注意它们有点重叠,尤其是y轴的部分)。

2 个回答

5

官方推荐的做法是:

  1. ax.tick_params(axis='z', pad=50)
  2. ax.set_zlabel(r'k_z...', labelpad=30)

不过,这里有点不太顺利。根据1.3.1版本的官方文档,使用tick_params时提到:虽然这个功能现在可以用,但Axes3D对象的核心部分可能会忽略其中的一些设置。看起来pad就是被忽略的其中之一。

而对于set_zlabel,文档中说:目前,labelpad对标签没有影响。

不过,对于第二个问题,有一个简单的解决办法。虽然看起来不太美观,但确实能用:

ax.set_zlabel('\n' + r'$\epsilon-\omega_X[\gamma_p]$', linespacing=2.5)

你可以通过调整linespacing这个参数来改变位置。单位是文本行的高度。(注意,如果你进行交互式调整,除非你以某种方式改变文本,否则不会显示出来。)

对于z轴的刻度标签,你也可以用类似的技巧:

ax.set_zticklabels(["       "+tl.get_text() for tl in ax.get_zticklabels()])

这样你可以一步一步地调整位置。当然,在数学文本模式下,你也可以使用间距命令('\/')。

7

你可以用下面的代码把z轴移到左边,具体代码可以在这里找到:

tmp_planes = ax.zaxis._PLANES 
ax.zaxis._PLANES = ( tmp_planes[2], tmp_planes[3], 
                     tmp_planes[0], tmp_planes[1], 
                     tmp_planes[4], tmp_planes[5])
view_1 = (25, -135)
view_2 = (25, -45)
init_view = view_2
ax.view_init(*init_view)

你可以通过添加新的一行来控制标签与轴之间的距离,并设置linespacing

ax.set_xlabel('\n' + 'xlabel', linespacing=4)

下面是一个完整的例子:

#!/usr/bin/python3

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

import numpy as np

X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

tmp_planes = ax.zaxis._PLANES 
ax.zaxis._PLANES = ( tmp_planes[2], tmp_planes[3], 
                     tmp_planes[0], tmp_planes[1], 
                     tmp_planes[4], tmp_planes[5])
view_1 = (25, -135)
view_2 = (25, -45)
init_view = view_2
ax.view_init(*init_view)

ax.plot_surface(X, Y, Z)

ax.set_xlabel('\n' + 'xlabel', linespacing=4)
ax.set_ylabel('ylabel')

fig.tight_layout()

fig.savefig('test.png')

在这里输入图片描述

(不过要注意,zx和zy的网格在框的错误一侧。我不知道怎么解决这个问题)。

撰写回答