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

为箱线图设置特定Y轴及解决重叠等绘制问题

箱线图绘制时间序列数据的问题解决

问题说明

尝试用箱线图绘制随时间(百万年单位)变化的数据时,遇到以下问题:

  • 箱线图互相重叠,无法锁定Y轴范围
  • 指定代表百万年的位置(如2.5)绘制时,箱线图过度聚集且尺寸过大,添加子图也无法解决

原始代码如下:

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

#default theme
sns.set_theme()

#Loading data set
my_data = pd.read_csv("C:\Users\tchat\OneDrive\Documents\UQAM_MS\Samples\Ratio\CSV\NbTa_ages_test.csv")

#see dataset
print(my_data)

#Check for non numerical data
non_numeric_columns = my_data.select_dtypes(exclude=[float,int]).columns
if len(non_numeric_columns) > 0:
    print(f"Non-numeric columns detected: {list(non_numeric_columns)}")
    my_data[non_numeric_columns]=my_data[non_numeric_columns].apply(pd.to_numeric, errors='coerce')

#Check for missing values
if my_data.isnull().values.any():
    print("Missing values detected, filling with column means.")
    my_data = my_data.fillna(my_data.mean())

#Number of columns in the dataset
num_columns = len(my_data.columns)
print(f"Number of columns: {num_columns}")

positions = [2.420, 2.458, 2.460, 2.461, 2.471, 2.472, 2.475, 2.476, 2.477, 2.478,2.480, 2.481, 2.482, 2.485, 2.5]

if len(positions) != num_columns:
    raise ValueError(f"The length of positions ({len(positions)}) does not match the number of columns in the data ({num_columns}).")

ax = my_data.boxplot(positions=positions, vert=False)

ax.set_ylim(2.4,2.5)

plt.grid(True, axis='y', which='major', linestyle='-', linewidth=0.5)
plt.grid(True, axis='y', which='minor', linestyle=':', linewidth=0.5)

plt.show()

输出的箱线图表现为多个箱体严重重叠,在2.4-2.5的Y轴区间内聚集在一起,尺寸过大导致无法区分单个箱体。

解决方案

1. 缩小箱线图宽度,避免重叠

使用boxplot的widths参数设置更小的箱体宽度,适配密集的时间位置。

2. 手动控制Y轴刻度与范围

由于时间位置的数值范围极小(仅0.1的跨度),matplotlib自动刻度逻辑会导致显示异常,需手动设置主/次刻度,确保Y轴锁定在目标范围。

3. 转换数据格式适配Seaborn(更推荐)

Pandas原生boxplot在处理密集数值位置时灵活性不足,改用Seaborn的boxplot需要先将宽格式数据转为长格式(通过pd.melt),这样更便于按时间轴映射箱体位置。

修改后的代码

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator

# 设置主题
sns.set_theme()

# 加载数据(路径加r避免转义问题)
my_data = pd.read_csv(r"C:\Users\tchat\OneDrive\Documents\UQAM_MS\Samples\Ratio\CSV\NbTa_ages_test.csv")

# 处理非数值与缺失值(保留原有逻辑)
non_numeric_columns = my_data.select_dtypes(exclude=[float, int]).columns
if len(non_numeric_columns) > 0:
    print(f"检测到非数值列: {list(non_numeric_columns)}")
    my_data[non_numeric_columns] = my_data[non_numeric_columns].apply(pd.to_numeric, errors='coerce')

if my_data.isnull().values.any():
    print("检测到缺失值,使用列均值填充。")
    my_data = my_data.fillna(my_data.mean())

# 为列名匹配时间位置,转换为长格式数据
positions = [2.420, 2.458, 2.460, 2.461, 2.471, 2.472, 2.475, 2.476, 2.477, 2.478, 2.480, 2.481, 2.482, 2.485, 2.5]
my_data.columns = positions
melted_data = my_data.melt(var_name="时间(Ma)", value_name="数值")

# 创建绘图对象并设置尺寸
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制箱线图,设置宽度避免重叠
sns.boxplot(data=melted_data, y="时间(Ma)", x="数值", vert=False, width=0.3, ax=ax)

# 锁定Y轴范围,手动设置刻度
ax.set_ylim(2.4, 2.5)
ax.yaxis.set_major_locator(MultipleLocator(0.01))
ax.yaxis.set_minor_locator(MultipleLocator(0.005))

# 添加网格
ax.grid(True, axis='y', which='major', linestyle='-', linewidth=0.5)
ax.grid(True, axis='y', which='minor', linestyle=':', linewidth=0.5)

# 优化布局
plt.tight_layout()
plt.show()

关键修改说明

  • 用pd.melt将宽格式数据转为长格式,让Seaborn可以直接映射时间轴为Y轴
  • 设置width=0.3缩小箱体宽度,避免密集位置的重叠
  • 手动设置Y轴主/次刻度,确保轴范围锁定且刻度清晰
  • 使用plt.tight_layout()优化布局,避免元素溢出

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:07:35