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

匹配两个DataFrame数据并在箱线图添加文本的实现及报错排查

问题解决:箱线图顶部添加匹配DataFrame的文本并修复ConversionError

错误原因分析

  1. 直接报错原因:原代码中mean[xtick]返回的是(组名, 对应Series)的元组,matplotlib无法将该元组转换为y轴的数值单位,因此抛出ConversionError。
  2. 数据匹配逻辑缺陷:原代码通过18*i+j的索引计算无法准确定位到df1中满足A == df2['num']且C == df2['S']的行,匹配逻辑不符合数据结构。

完整解决方案代码

import pandas as pd
import numpy as np
import seaborn as sns 
import matplotlib.pyplot as plt 

np.random.seed(12)

# 修正数据生成笔误:col_a改为col_a1
col_a1 = [i for i in range(18)] * 15  
col_b1 = np.random.randint(1, 100, len(col_a1))
configs = ['c1', 'c2', 'c3', 'c4']
col_c1 = [configs[i//90] + '_' + f'abctrct{i//18}' for i in range(len(col_a1))]
df1 = pd.DataFrame({'A': col_a1, 'B': col_b1, 'C': col_c1})

# 生成第二个DataFrame
col_d2 = [s + '-' +f'{np.random.randint(1,18)}' for s in list(set(col_c1))]
df2 = pd.DataFrame({'D': col_d2, 'E': np.random.randint(100, 200, len(col_d2))})

# 拆分df1的C列,用于绘图分组
df1[['Hue', 'X']] = df1['C'].str.split('_', expand=True)

# 绘制图形:添加dodge=True确保不同Hue的图形对齐
fig, ax  = plt.subplots(figsize=(12,6))
sns.stripplot(y='B', x='X', data=df1, hue='Hue', dodge=True)
sns.boxplot(y='B', x='X', data=df1, hue='Hue', dodge=True)
plt.xticks(rotation=45, ha='right')

# ---------------------- 数据匹配:获取需要显示的B和A值 ----------------------
# 拆分df2的D列,提取匹配标识和A值
df2[['S', 'num']] = df2['D'].str.split('-', expand=True)
df2['num'] = df2['num'].astype(int)

# 拆分S为Hue和X,与df1保持一致,方便关联
df2[['Hue', 'X']] = df2['S'].str.split('_', expand=True)

# 合并df1和df2,精准匹配满足条件的行
merged = pd.merge(df1, df2, left_on=['C', 'A'], right_on=['S', 'num'], how='inner')
display_data = merged[['X', 'Hue', 'B', 'A']].drop_duplicates()

# ---------------------- 定位箱线位置,添加文本 ----------------------
# 建立X类别与x轴位置的映射
x_categories = ax.get_xticklabels()
x_pos_dict = {label.get_text(): idx for idx, label in enumerate(x_categories)}

# 计算不同Hue的偏移量(适配dodge=True的布局)
box_width = 0.8
n_hues = len(df1['Hue'].unique())
dodge_width = box_width / n_hues
hue_order = ['c1', 'c2', 'c3', 'c4']
hue_pos_dict = {hue: -box_width/2 + dodge_width/2 + i*dodge_width for i, hue in enumerate(hue_order)}

# 遍历每个匹配项,添加带边框的文本
for _, row in display_data.iterrows():
    x_base = x_pos_dict[row['X']]
    x_pos = x_base + hue_pos_dict[row['Hue']]
    
    # 获取对应箱线的顶部y坐标
    box_top = None
    for patch in ax.artists:
        box_center_x = patch.get_x() + patch.get_width()/2
        if abs(box_center_x - x_pos) < 0.1:
            box_top = patch.get_y() + patch.get_height()
            break
    if not box_top:
        box_top = df1['B'].max() * 1.1  #  fallback到y轴最大值上方
    
    # 添加B值文本
    ax.text(x_pos, box_top + 2, f'B={row["B"]}', 
            horizontalalignment='center', verticalalignment='bottom', 
            fontsize=10, bbox={'facecolor': 'green', 'alpha': 0.5, 'pad': 3})
    # 添加A值文本
    ax.text(x_pos, box_top + 6, f'A={row["A"]}', 
            horizontalalignment='center', verticalalignment='bottom', 
            fontsize=10, bbox={'facecolor': 'yellow', 'alpha': 0.5, 'pad': 3})

plt.tight_layout()
plt.show()

关键修复说明

  1. 修正数据生成笔误:将原代码中的col_a改为col_a1,避免运行时索引长度不匹配的错误。
  2. 图形对齐优化:为stripplot和boxplot添加dodge=True,确保不同Hue的图形横向对齐,方便后续文本定位。
  3. 精准数据匹配:使用pd.merge替代原有的索引计算,通过C和A字段精准关联两个DataFrame,避免索引逻辑错误。
  4. 解决坐标错误:通过遍历matplotlib的艺术家对象(ax.artists)获取每个箱线的实际顶部y坐标,替代原代码中错误的元组值,彻底解决ConversionError。
  5. 文本定位适配:计算每个Hue的横向偏移量,确保文本准确对应到所属的箱线位置。

内容的提问来源于stack exchange,提问作者A.E

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:34:56