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

Seaborn箱线图与散点图跨子图对齐问题:调整温度子图散点位置以匹配箱线图宽度

Seaborn箱线图与散点图跨子图对齐问题:调整温度子图散点位置以匹配箱线图宽度

我明白你的问题啦——你为了让温度和设计两个子图的箱线图、散点宽度保持一致,特意调整了箱线图的width参数,但温度图的散点却跑到箱线外面去了对吧?这是因为stripplot的dodge=True是基于默认的箱线图宽度来计算偏移量的,当你自定义了箱线图宽度后,自动偏移就和箱线图的实际宽度不匹配了。

解决方案:手动指定散点的位置偏移

我们可以放弃自动的dodge,改用position参数手动计算每个hue组(exp和sim)的位置,让散点正好落在对应的箱线图内部。核心思路是:根据自定义的箱线图宽度,计算每个hue组的偏移量,确保两个散点组的总宽度和箱线图宽度完全一致。

修改后的完整代码

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

n = 200 

value = np.random.rand(n).tolist()
design = np.random.choice([1,2,3,4,5], size=n)
temp = np.random.choice([-100.0, 100.0], size=n)
indices = np.random.choice(['exp', 'sim'], size=n)

frame_scatter = {"design": design, "temp": temp, 'Measured_Value': value}
frame_scatter = pd.DataFrame(data=frame_scatter, index=indices)
frame_scatter.index.name = 'Index_Name'

single_box = 0.16
custom_width_box= {
    'design': single_box * 5,  # 只保留宽度值,偏移量我们手动计算
    'temp': single_box * 2,
}

categories = ['temp', 'design']
palette = ['r', 'g']  # 对应exp和sim的颜色

for c_category in categories:
    plt.figure(figsize=(6.4, 4.8), dpi=400)
    box_width = custom_width_box[c_category]
    
    # 1. 画箱线图
    c_ax = sns.boxplot(
        data=frame_scatter, x=c_category, y='Measured_Value', hue="Index_Name",
        showfliers=False, palette=palette, boxprops={'alpha': 0.4}, 
        width=box_width
    )
    
    # 2. 计算散点的位置偏移
    x_cats = sorted(frame_scatter[c_category].unique())
    x_pos = np.arange(len(x_cats))  # 获取每个x类别的默认位置(0,1,2...)
    offset = box_width / 4  # 两个hue组各偏移1/4宽度,总覆盖宽度等于箱线图宽度
    
    # 3. 分别画exp和sim的散点,手动指定位置
    for i, (hue_val, color) in enumerate(zip(['exp', 'sim'], palette)):
        subset = frame_scatter[frame_scatter.index == hue_val]
        # 给exp左偏,sim右偏(或者反过来,看你想要的顺序)
        scatter_pos = x_pos + (-offset if i == 0 else offset)
        sns.stripplot(
            data=subset, x=c_category, y='Measured_Value', color=color,
            ax=c_ax, jitter=box_width/3, position=scatter_pos, legend=False
        )
    
    # 4. 调整图例
    handles, labels = c_ax.get_legend_handles_labels()
    c_ax.legend(
        handles=[(handles[0], handles[2]), (handles[1], handles[3])], 
        labels=['exp', 'sim'], loc='upper left', handlelength=4, 
        handler_map={tuple: matplotlib.legend_handler.HandlerTuple(ndivide=None)}
    )
    plt.grid()
    plt.show()

关键修改点说明

  • 移除冗余配置:删掉了custom_width_box中未使用的偏移列表,只保留核心的宽度值,让代码更简洁。
  • 手动计算散点位置:
    • 先获取x轴类别的默认位置(x_pos)
    • 以箱线图宽度的1/4作为偏移量(offset = box_width /4),确保两个hue组的散点总宽度与箱线图宽度完全匹配
  • 分组绘制散点:不再依赖dodge=True的自动偏移,改用position参数手动指定每个hue组的位置,让散点精准落在箱线图内部
  • 保持抖动范围匹配:jitter值仍使用box_width/3,确保散点的抖动范围不会超出箱线图的宽度范围

这样修改后,温度图的散点就会和设计图的散点一样,正好对应落在各自的箱线图内部,两个子图的视觉宽度也能保持一致啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 18:38:14