You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib雷达图xtick标签遮挡截断问题解决求助

Matplotlib雷达图长标签重叠/截断问题的两种解决方案

我从Stack Overflow找到一个Python Matplotlib雷达图绘制示例,当前xtick标签过长,伸入雷达图内部被线条遮挡,部分标签还被图表区域截断。试过plt.tight_layout()无效,现提供两种解决方案:


方案1:将标签移至雷达图外侧(优先方案)

通过调整刻度标签的内边距和对齐方式,让标签完全显示在雷达图外部,彻底避免与图表重叠。关键修改点:

  • 增大标签与雷达图的间距(pad参数)
  • 根据极坐标角度为每个标签设置对应的水平/垂直对齐方式,保证排版整齐
  • 扩大图表尺寸,为外侧标签预留足够显示空间

修改后的完整代码:

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt

def create_radar(df, *, id_column, title=None, max_values=None, padding=1.25, width=12, length=12):
    cm = 1/2.54
    categories = df._get_numeric_data().columns.tolist()
    data = df[categories].to_dict(orient='list')
    ids = df[id_column].tolist()
    if max_values is None:
        max_values = {key: padding*max(value) for key, value in data.items()}

    normalized_data = {key: np.array(value) / max_values[key] for key, value in data.items()}
    num_vars = len(data.keys())
    tiks = list(data.keys())
    angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
    fig, ax = plt.subplots(figsize=(width*cm, length*cm), subplot_kw=dict(polar=True))

    for i, model_name in enumerate(ids):
        values = [normalized_data[key][i] for key in data.keys()]
        actual_values = [data[key][i] for key in data.keys()]
        values += values[:1]  # 闭合雷达图
        ax.plot(angles + [angles[0]], values, label=model_name)
        ax.fill(angles + [angles[0]], values, alpha=0.15)
        for _x, _y, t in zip(angles, values[:-1], actual_values):
            if isinstance(t, float) and t > 1:
                t = f'{t:.0f}'
            elif isinstance(t, float) and t <= 1:
                t = f'{t:.2%}'
            else:
                str(t)
            if i % 2 == 0:
                ax.text(_x, _y+.02, t, size='xx-small', va='top', ha='right')
            else:
                ax.text(_x, _y-.02, t, size='xx-small', va='bottom', ha='left')

    ax.fill(angles + [angles[0]], np.ones(num_vars + 1), alpha=0.05)
    ax.set_yticklabels([])
    ax.set_xticks(angles)
    
    # 核心修改:调整标签位置与对齐方式
    ax.tick_params(axis='x', pad=15)  # 增大标签与雷达图的距离
    tick_labels = []
    for angle, label in zip(angles, tiks):
        # 根据角度动态设置对齐方式
        if angle == 0:
            ha, va = 'left', 'center'
        elif np.pi/2 < angle < np.pi:
            ha, va = 'right', 'top'
        elif angle == np.pi:
            ha, va = 'right', 'center'
        elif np.pi < angle < 3*np.pi/2:
            ha, va = 'right', 'bottom'
        elif angle == 3*np.pi/2:
            ha, va = 'center', 'bottom'
        else:
            ha, va = 'left', 'top'
        tick_labels.append(plt.Text(angle, 1, label, ha=ha, va=va, size="xx-small"))
    ax.set_xticklabels(tick_labels)
    
    ax.legend(loc='lower right')

    if title is not None:
        plt.suptitle(title)
    plt.tight_layout(pad=2)
    plt.show()

create_radar(
    pd.DataFrame({
        'x': [*'abcde'],
        'supeeeer long category name 1': [10,11,12,13,14],
        'supeeeer long category name 2': [0.1, 0.3, 0.4, 0.1, 0.9],
        'supeeeer long category name 4': [1e5, 2e5, 3.5e5, 8e4, 5e4],
        'supeeeer long category name 5': [9, 12, 5, 2, 0.2],
        'supeeeer long category name 6': [1,1,1,1,5]
    }),
    id_column='x',
)

方案2:将标签置于图表前端并完整显示

若不想移动标签位置,可通过设置标签层级让其显示在图表线条上方,同时调整布局避免标签被截断。关键修改点:

  • 给标签设置更高的zorder层级,确保显示在图表元素之上
  • 降低雷达图线条和填充的层级,避免遮挡标签
  • 调整子图位置,为标签预留显示空间

修改后的完整代码:

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt

def create_radar(df, *, id_column, title=None, max_values=None, padding=1.25, width=12, length=12):
    cm = 1/2.54
    categories = df._get_numeric_data().columns.tolist()
    data = df[categories].to_dict(orient='list')
    ids = df[id_column].tolist()
    if max_values is None:
        max_values = {key: padding*max(value) for key, value in data.items()}

    normalized_data = {key: np.array(value) / max_values[key] for key, value in data.items()}
    num_vars = len(data.keys())
    tiks = list(data.keys())
    angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
    fig, ax = plt.subplots(figsize=(width*cm, length*cm), subplot_kw=dict(polar=True))

    for i, model_name in enumerate(ids):
        values = [normalized_data[key][i] for key in data.keys()]
        actual_values = [data[key][i] for key in data.keys()]
        values += values[:1]  # 闭合雷达图
        # 降低图表元素层级,避免遮挡标签
        ax.plot(angles + [angles[0]], values, label=model_name, zorder=1)
        ax.fill(angles + [angles[0]], values, alpha=0.15, zorder=1)
        for _x, _y, t in zip(angles, values[:-1], actual_values):
            if isinstance(t, float) and t > 1:
                t = f'{t:.0f}'
            elif isinstance(t, float) and t <= 1:
                t = f'{t:.2%}'
            else:
                str(t)
            if i % 2 == 0:
                ax.text(_x, _y+.02, t, size='xx-small', va='top', ha='right', zorder=2)
            else:
                ax.text(_x, _y-.02, t, size='xx-small', va='bottom', ha='left', zorder=2)

    ax.fill(angles + [angles[0]], np.ones(num_vars + 1), alpha=0.05, zorder=0)
    ax.set_yticklabels([])
    ax.set_xticks(angles)
    
    # 核心修改:设置标签层级与对齐方式
    tick_labels = []
    for angle, label in zip(angles, tiks):
        if angle == 0:
            ha, va = 'right', 'center'
        elif np.pi/2 < angle < np.pi:
            ha, va = 'left', 'top'
        elif angle == np.pi:
            ha, va = 'left', 'center'
        elif np.pi < angle < 3*np.pi/2:
            ha, va = 'left', 'bottom'
        elif angle == 3*np.pi/2:
            ha, va = 'center', 'top'
        else:
            ha, va = 'right', 'top'
        # 设置标签zorder为10,确保显示在最上层
        tick_labels.append(plt.Text(angle, 1, label, ha=ha, va=va, size="xx-small", zorder=10))
    ax.set_xticklabels(tick_labels)
    
    ax.legend(loc='lower right', zorder=11)

    if title is not None:
        plt.suptitle(title)
    # 调整子图位置,预留标签显示空间
    plt.subplots_adjust(left=0.15, right=0.15, top=0.9, bottom=0.15)
    plt.show()

create_radar(
    pd.DataFrame({
        'x': [*'abcde'],
        'supeeeer long category name 1': [10,11,12,13,14],
        'supeeeer long category name 2': [0.1, 0.3, 0.4, 0.1, 0.9],
        'supeeeer long category name 4': [1e5, 2e5, 3.5e5, 8e4, 5e4],
        'supeeeer long category name 5': [9, 12, 5, 2, 0.2],
        'supeeeer long category name 6': [1,1,1,1,5]
    }),
    id_column='x',
)

内容的提问来源于stack exchange,提问作者Maeaex1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 13:00:54