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

如何在同一绘图中显示两个不同尺度的Seaborn计数图且避免柱子重叠?

解决Seaborn双尺度countplot柱子重叠/宽度不一致的问题

这问题我之前也碰到过!当你尝试在同一张图里叠加两个尺度差异大的Seaborn countplot时,默认的布局逻辑确实会让柱子宽度不一、互相重叠,dodge=False只会让它们完全叠在一起,根本没法看。试试下面这两个靠谱的解决办法:

方法一:双Y轴+手动调整柱子位置与宽度

核心思路是用双Y轴分别对应两个数据集的尺度,然后手动控制两组柱子的位置和宽度,让它们并排显示而不重叠。具体步骤如下:

  1. 先绘制第一个countplot,绑定到左侧Y轴;
  2. 获取第一组柱子的位置和宽度,计算第二组柱子的偏移位置(比如偏移第一组宽度的一半);
  3. 用barplot(countplot本质是封装好的barplot)绘制第二组数据的计数,绑定到右侧Y轴,同时调整宽度;
  4. 最后统一调整图例、轴标签等细节。

示例代码:

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

# 构造示例数据集(模拟尺度差异)
df_small = pd.DataFrame({'category': ['A', 'B', 'C', 'A', 'B', 'B']})
df_large = pd.DataFrame({'category': ['A']*8 + ['B']*12 + ['C']*10})

# 绘制第一个countplot(左Y轴)
fig, ax_left = plt.subplots(figsize=(8, 5))
sns.countplot(data=df_small, x='category', ax=ax_left, color='#63aeee', label='小尺度数据集')
ax_left.set_ylabel('计数(小尺度)')
ax_left.set_xlabel('类别')

# 获取第一组柱子的位置和宽度参数
bars_left = ax_left.patches
bar_width = bars_left[0].get_width()
original_pos = [bar.get_x() for bar in bars_left]

# 计算第二组柱子的偏移位置(让两组柱子并排)
shifted_pos = [pos + bar_width/2 for pos in original_pos]

# 计算第二组数据的计数(确保类别顺序和第一组一致)
large_counts = df_large['category'].value_counts().reindex(df_small['category'].unique())

# 绘制第二个barplot(右Y轴)
ax_right = ax_left.twinx()
ax_right.bar(shifted_pos, large_counts, width=bar_width/2, color='#f27970', label='大尺度数据集')
ax_right.set_ylabel('计数(大尺度)')

# 合并两组图例
handles_left, labels_left = ax_left.get_legend_handles_labels()
handles_right, labels_right = ax_right.get_legend_handles_labels()
ax_left.legend(handles_left + handles_right, labels_left + labels_right, loc='upper right')

plt.tight_layout()
plt.show()

方法二:标准化其中一组数据(保留原始值标注)

如果不想用双Y轴,也可以把其中一组数据的计数标准化到另一组的尺度范围内,然后在柱子上标注原始数值。这种方法适合需要统一Y轴视觉效果的场景:

示例代码:

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

df_small = pd.DataFrame({'category': ['A', 'B', 'C', 'A', 'B', 'B']})
df_large = pd.DataFrame({'category': ['A']*8 + ['B']*12 + ['C']*10})

# 计算两组数据的计数
small_counts = df_small['category'].value_counts().reindex(['A', 'B', 'C'])
large_counts = df_large['category'].value_counts().reindex(['A', 'B', 'C'])

# 标准化大尺度数据到小尺度的范围(这里用最大值比例)
scale_ratio = small_counts.max() / large_counts.max()
normalized_large = large_counts * scale_ratio

# 绘制两组柱子
fig, ax = plt.subplots(figsize=(8, 5))
sns.barplot(x=['A', 'B', 'C'], y=small_counts, ax=ax, width=0.35, color='#63aeee', label='小尺度数据集')
sns.barplot(x=[x+0.35 for x in range(3)], y=normalized_large, ax=ax, width=0.35, color='#f27970', label='大尺度数据集(标准化)')

# 标注原始大尺度数值
for i, count in enumerate(large_counts):
    ax.text(i+0.35, normalized_large[i]+0.1, f'{count}', ha='center')

ax.set_ylabel('计数(小尺度/标准化后)')
ax.set_xlabel('类别')
ax.legend()
plt.tight_layout()
plt.show()

这两种方法都能完美解决柱子重叠、宽度不一致的问题,你可以根据自己的可视化需求选择~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 06:55:23