You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何修正Matplotlib 3D折线图中标签位置以实现预期效果

如何修正Matplotlib 3D折线图中标签位置以实现预期效果

我有一段生成3D折线图的代码,尝试给折线添加标签,但标签位置总是不符合预期:

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

# Data
names = [
    "A", "B", "C", "D", "E", "F",
    "G", "H", "I", "J", "K", "L"
]
wins = [
    [0, 14, 20, 24, 29, 33, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39],
    [0, 7, 13, 17, 23, 27, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
    [0, 5, 8, 11, 15, 16, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19],
    [0, 7, 11, 17, 20, 25, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29],
    [0, 9, 14, 22, 29, 36, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42],
    [0, 6, 10, 16, 20, 24, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29],
    [0, 7, 13, 20, 26, 31, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34],
    [0, 10, 13, 18, 24, 29, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33],
    [0, 5, 11, 13, 16, 21, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26],
    [0, 12, 15, 18, 21, 25, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
    [0, 9, 11, 12, 17, 20, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26],
    [0, 15, 20, 25, 27, 33, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37],
]
weeks = [f"Week{i+1}" for i in range(18)]  # X-axis categories (nb of weeks)

# Convert names into numerical indices for the Y-axis
x = np.arange(len(weeks))      # X-axis 
y = np.arange(len(names))      # Y-axis 
wins_array = np.array(wins)    # wins accumulated per weeks and per names

# Create a 3D plot
fig = plt.figure(figsize=(18, 18))
ax = fig.add_subplot(111, projection='3d')

# Plot each line and add labels
for i, y_week in enumerate(y):
    ax.plot(x, wins_array[i], zs=y_week, zdir='x', label=weeks[i])
    # Add shaded area below the line
    ax.bar(x, wins_array[i], zs=y_week, zdir='x', alpha=0.1)
    # Add labels directly on the curves
    for j, my_label in enumerate(wins_array[i]):
        ax.text(i, my_label, y_week, f"{my_label}", color="red", fontsize=8, ha="center")

# Customize labels
ax.set_zlabel('Wins')              # Z-axis is wins
ax.set_xticks(y)                   # X-ticks are names
ax.set_xticklabels(names, rotation=45)  # Name labels on X-axis
ax.set_yticks(x)                   # Y-ticks are weeks
ax.set_yticklabels(weeks)          # Week labels on Y-axis

plt.show()

当前的效果:
当前3D折线图效果

我想要实现的效果:
预期的3D折线图效果

请问如何修改代码来达到预期效果?


问题分析与修正方案

你的问题主要出在3D文本的坐标顺序标签逻辑上,我帮你一步步调整:

1. 修正3D文本的坐标顺序

Matplotlib的ax.text()方法参数顺序是(x, y, z),但你之前完全搞混了坐标对应关系:

  • X轴对应names(即代码中的y数组元素)
  • Y轴对应weeks(即代码中的x数组元素)
  • Z轴对应wins(即wins_array中的数值)
    所以你之前的ax.text(i, my_label, y_week)顺序错误,需要调整为符合轴定义的坐标。

2. 调整标签逻辑(贴合预期图)

你原来给每个数据点都加了红色标签,而预期图是在每条折线末端添加对应的名称(A、B等),所以我们不需要循环每个点,只在折线的最后一个位置添加标签即可,还能避免画面杂乱。

修正后的完整代码

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

# Data
names = [
    "A", "B", "C", "D", "E", "F",
    "G", "H", "I", "J", "K", "L"
]
wins = [
    [0, 14, 20, 24, 29, 33, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39],
    [0, 7, 13, 17, 23, 27, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
    [0, 5, 8, 11, 15, 16, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19],
    [0, 7, 11, 17, 20, 25, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29],
    [0, 9, 14, 22, 29, 36, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42],
    [0, 6, 10, 16, 20, 24, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29],
    [0, 7, 13, 20, 26, 31, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34],
    [0, 10, 13, 18, 24, 29, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33],
    [0, 5, 11, 13, 16, 21, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26],
    [0, 12, 15, 18, 21, 25, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
    [0, 9, 11, 12, 17, 20, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26],
    [0, 15, 20, 25, 27, 33, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37],
]
weeks = [f"Week{i+1}" for i in range(18)]  # X-axis categories (nb of weeks)

# 明确轴对应关系:y是名称索引(X轴),x是周数索引(Y轴)
y = np.arange(len(names))      # X轴:名称的索引
x = np.arange(len(weeks))      # Y轴:周数的索引
wins_array = np.array(wins)    # Z轴:累计获胜数

# 创建3D画布
fig = plt.figure(figsize=(18, 18))
ax = fig.add_subplot(111, projection='3d')

# 遍历每个名称对应的折线
for i, name_idx in enumerate(y):
    # 绘制折线:zdir='x'表示X轴对应name_idx
    ax.plot(x, wins_array[i], zs=name_idx, zdir='x', label=names[i])
    # 添加折线下方的阴影区域
    ax.bar(x, wins_array[i], zs=name_idx, zdir='x', alpha=0.1)
    # 在折线最后一个点的右侧添加名称标签
    last_week = x[-1]
    last_win = wins_array[i][-1]
    ax.text(name_idx, last_week + 0.5, last_win, names[i],
            color="black", fontsize=10, ha="center", va="center")

# 自定义轴标签
ax.set_zlabel('Wins')              # Z轴:获胜数
ax.set_xticks(y)                   # X轴刻度:名称索引
ax.set_xticklabels(names, rotation=45)  # X轴刻度标签:名称
ax.set_yticks(x)                   # Y轴刻度:周数索引
ax.set_yticklabels(weeks)          # Y轴刻度标签:周数

plt.show()

关键修正点说明

  • 调整了ax.text()的坐标顺序,让标签对应正确的3D轴位置,同时给Y轴坐标加了0.5,让标签稍微靠右,避免和折线重叠
  • 只在每条折线的末端添加名称标签,和你预期的效果一致
  • 修正了折线的label为对应的名称,如需图例可以取消注释ax.legend()
  • 调整了标签的颜色和字号,提升可读性

这样修改后,你的3D折线图标签位置就会和预期效果匹配啦!

备注:内容来源于stack exchange,提问作者Ma Poub

火山引擎 最新活动