避免"散点/点/蜜蜂群"图中数据点重叠

63 投票
7 回答
83698 浏览
提问于 2025-04-17 09:13

在使用 matplotlib 绘制点图时,我想把重叠的数据点稍微偏移一下,这样它们就都能看得见了。比如说,如果我有:

CategoryA: 0,0,3,0,5  
CategoryB: 5,10,5,5,10  

我希望每个 CategoryA 的 "0" 数据点能够并排显示,而不是重叠在一起,同时还要和 CategoryB 区分开来。

在 R 语言的 ggplot2 中,有一个叫 "jitter" 的选项可以做到这一点。请问在 matplotlib 中有没有类似的选项,或者有没有其他方法可以达到类似的效果呢?

编辑:为了更清楚,我想说的是,R 语言中的 "beeswarm" 正是我想要的效果,而 pybeeswarm 是一个早期但很有用的 matplotlib/Python 版本。

编辑:补充一下,Seaborn 的 Swarmplot,在 0.7 版本中引入,是我想要的效果的一个很好的实现。

7 个回答

15

我使用了numpy.random这个库来把数据在X轴上“散开”或者说“像蜜蜂一样聚集”,但是每个类别的数据都是围绕一个固定的点分布的。然后,我对每个类别的数据基本上都用pyplot.scatter()这个函数来绘制散点图:

import matplotlib.pyplot as plt
import numpy as np

#random data for category A, B, with B "taller"
yA, yB = np.random.randn(100), 5.0+np.random.randn(1000)

xA, xB = np.random.normal(1, 0.1, len(yA)), 
         np.random.normal(3, 0.1, len(yB))

plt.scatter(xA, yA)
plt.scatter(xB, yB)
plt.show()

X-scattered data

22

Seaborn这个库可以通过 sns.swarmplot() 来制作类似直方图的分类点图,同时也可以用 sns.stripplot() 来制作带有抖动效果的分类点图:

import seaborn as sns

sns.set(style='ticks', context='talk')
iris = sns.load_dataset('iris')

sns.swarmplot('species', 'sepal_length', data=iris)
sns.despine()

enter image description here

sns.stripplot('species', 'sepal_length', data=iris, jitter=0.2)
sns.despine()

enter image description here

63

在@user2467675的回答基础上,我来分享一下我是怎么做的:

def rand_jitter(arr):
    stdev = .01 * (max(arr) - min(arr))
    return arr + np.random.randn(len(arr)) * stdev

def jitter(x, y, s=20, c='b', marker='o', cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, verts=None, hold=None, **kwargs):
    return scatter(rand_jitter(x), rand_jitter(y), s=s, c=c, marker=marker, cmap=cmap, norm=norm, vmin=vmin, vmax=vmax, alpha=alpha, linewidths=linewidths, **kwargs)

stdev这个变量是用来确保抖动效果足够明显,可以在不同的比例下看到,但它假设坐标轴的范围是从零到最大值。

接着,你可以用jitter来代替scatter

撰写回答