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

如何在含极端异常值的箱线图中截断坐标轴?

带极端异常值的箱线图X轴截断实现方案

问题背景

用matplotlib+seaborn绘制箱线图时,因存在2000天的极端异常值,X轴范围被拉得过大,导致箱型占比极小。需要在700-1750区间截断X轴(用双斜杠标记),既保留异常值,又放大展示正常数据的箱型。此前尝试将列重命名为days_after并生成days_before列,拆分X轴绘图失败,现提供可行解决方法。

示例数据集

import pandas as pd
data = { 
    'T1': ['ja', 'ja', 'ja', 'ja', 'ja', 'nein', 'nein', 'nein', 'nein', 'nein', 
           'ja', 'ja', 'ja', 'ja', 'ja', 'nein', 'nein', 'nein', 'nein', 'nein', 
           'ja', 'ja', 'ja', 'ja', 'ja', 'nein', 'nein', 'nein', 'nein'], 
    'days': [2000,200,200,400,400,100,500,50,400,600,30,200,200,400,400,
             100,100,50,400,600,30,200,200,400,400,100,100,50,400]
}
df = pd.DataFrame(data)

初始绘图代码(问题复现)

import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

f, ax = plt.subplots(figsize=(15,5))
sns.boxplot(data=df,
            x='days',
            y='T1',
            hue='T1',
            ax=ax)

ax.set_xlabel('days')
ax.legend().remove()
plt.show()

此前尝试的问题分析

之前的代码存在两处关键错误:

  • 未定义days_after列就直接使用,导致报错
  • 用负数反转数据的逻辑不合理,拆分后的X轴范围设置与需求不匹配,无法实现正常数据区与异常值区的分离展示

可行解决方案

方案一:使用matplotlib原生断轴功能(推荐)

通过创建共享Y轴的两个子图,分别展示正常数据区和异常值区,再添加截断标记模拟断轴效果。

import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

# 创建两个共享Y轴的子图,调整宽度比例(正常数据区占比更大)
fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True, figsize=(10,5),
                               gridspec_kw={'width_ratios': [4, 1]})

# 左轴绘制正常数据(隐藏异常值)
sns.boxplot(data=df, x='days', y='T1', hue='T1', ax=ax1, showfliers=False)
# 右轴绘制全量数据(仅显示异常值及附近范围)
sns.boxplot(data=df, x='days', y='T1', hue='T1', ax=ax2)

# 移除冗余图例
ax1.legend().remove()
ax2.legend().remove()

# 设置X轴范围:左轴显示0-700,右轴显示1750-2100
ax1.set_xlim(0, 700)
ax2.set_xlim(1750, 2100)

# 隐藏中间边框,模拟截断效果
ax1.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.yaxis.set_ticks_position('none')  # 隐藏右轴Y刻度

# 添加截断标记(双斜杠)
d = .015  # 控制斜线倾斜程度
kwargs = dict(transform=ax1.transAxes, color='k', clip_on=False)
ax1.plot((1-d, 1+d), (-d, +d), **kwargs)
ax1.plot((1-d, 1+d), (1-d, 1+d), **kwargs)

kwargs.update(transform=ax2.transAxes)
ax2.plot((-d, +d), (1-d, 1+d), **kwargs)
ax2.plot((-d, +d), (-d, +d), **kwargs)

# 设置轴标签并调整子图间距
ax1.set_xlabel('days')
ax2.set_xlabel('')
plt.subplots_adjust(wspace=0.05)
plt.show()

方案二:数据拆分简化版

将异常值单独提取,用两个子图分别展示正常箱型和异常值点:

import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True, figsize=(10,5),
                               gridspec_kw={'width_ratios': [4, 1]})

# 左轴:正常数据箱线图
sns.boxplot(data=df[df['days']<=700], x='days', y='T1', hue='T1', ax=ax1)
# 右轴:仅绘制异常值(散点图展示)
sns.stripplot(data=df[df['days']>1750], x='days', y='T1', hue='T1', 
              ax=ax2, jitter=False, size=8)

# 移除图例并设置轴范围
ax1.legend().remove()
ax2.legend().remove()
ax1.set_xlim(0,700)
ax2.set_xlim(1750,2100)

# 隐藏中间边框并添加截断标记
ax1.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.yaxis.set_ticks_position('none')

d = .015
kwargs = dict(transform=ax1.transAxes, color='k', clip_on=False)
ax1.plot((1-d,1+d), (-d,+d), **kwargs)
ax1.plot((1-d,1+d), (1-d,1+d), **kwargs)

kwargs.update(transform=ax2.transAxes)
ax2.plot((-d,+d), (1-d,1+d), **kwargs)
ax2.plot((-d,+d), (-d,+d), **kwargs)

plt.subplots_adjust(wspace=0.05)
plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 17:04:55