散点图中,当点密集的区域仍然不透明时,如何设置alpha值?

5
我有一个散点图,它显示了来自两个不同数据集的大量点。在某些区域,有大量的点,即使使用非常低的alpha值(例如alpha=0.1),您也无法透过这一堆点看到后面的内容。但是,在那个alpha值下,你几乎看不到稀疏地区的点。有没有一种方法来限制堆积点的alpha值,或者以某种方式在不淡化稀疏区域的同时使得密集区域的背景可见?代码片段如下:
# Code to populate the datasets not included.
fig, ax = plt.subplots()
ax.scatter(x1, y1, s=12, color='red')
ax.scatter(x2, y2, s=12, color='blue', alpha=0.1)
# Plus code to do xlabels and such not included.

生成这个:

enter image description here

正如您所看到的,很难看出底部红色腿的边界,同时使顶部蓝色腿突出。

有没有办法创建这种效果?

提前感谢。

编辑

一个好的建议似乎是使用hexbin而不是scatter。这看起来很有希望,但颜色仍然不能很好地混合。例如,

ax.hexbin(x1, y1, cmap='Reds', mincnt=1, vmax=100)
ax.hexbin(x2, y2, cmap='Blues', mincnt=1, vmax=50, alpha=0.8, linewidths=0)

产生:

enter image description here

希望能够将蓝色和红色合并。也许每个像素可以从一个数据集中获取R值,从另一个数据集中获取B值?但在hexbin中似乎不是一个选项。

编辑

应用Thomasillo的答案后:

enter image description here

谢谢,我认为它比原来的看起来更好。


1
你可以考虑使用hexbin,就像这个例子中展示的那样。 - BrenBarn
1
@BrenBarn hexbin 在这里有什么用处?它是一个双组密度。我也不明白你链接的例子是否应该解决这个特定问题。 - Ami Tavory
你可以像使用两个散点图一样使用两个六边形图。如果你为两个六边形图使用不同的颜色映射,并将两者的透明度设置为非完全不透明的值,那么你就可以得到一些重叠的六边形图。我认为即使使用 alpha 值,散点图也不是这种具有大量重叠数据集的最佳选择。 - BrenBarn
我想到的一种解决方案是逐个绘制每个点,并根据某个半径内附近有多少个点来改变其 alpha 值。(最近邻?)当然,这将需要你针对每个点检查所有其他点 O(n^2),并且需要调整距离计数函数,然后你需要基于此创建一个 alpha 值(这是许多不必要的工作)。而且如果你更改了绘图的宽度/高度,这种方法也会有所变化。 - Bryce Guinta
我会尝试使用密度等高线图——这意味着像六边形散点图一样计算密度,但有时更容易阅读。 - cphlewis
1个回答

1

1) 为了改进六边形图,您可以使用选项 bins='log'。这会对六边形进行对数计算,有效地使低数字与高数字相比更加突出。

2) 自己计算每个数据集的密度。从两个密度中生成颜色,例如让一个密度影响红色通道,另一个密度影响蓝色通道。使用 imshow 绘制结果。

类似于

import matplotlib.pyplot as plt
import numpy as np
import itertools

x1 = np.random.binomial(5100,0.5,51100)
y1 = np.random.binomial(5000,0.7,51100)
x2 = np.random.binomial(5000,0.5,51100)
y2 = np.random.binomial(5000,0.7,51100)


xmin,xmax,xnum = 2350,2700,50
ymin,ymax,ynum = 3350,3700,50
xx,yy=np.mgrid[xmin:xmax:xnum*1j,ymin:ymax:ynum*1j]

def closest_idx(x,y):
    idcs    = np.argmin((xx-x)**2 + (yy-y)**2)
    i_x,i_y = np.unravel_index(idcs, (xnum,ynum) )
    return i_x,i_y

def calc_count( xdat,ydat ):
    ct = np.zeros_like(xx)
    for x,y in itertools.izip(xdat,ydat):
        ix,iy = closest_idx(x,y)
        ct [ix,iy] += 1
    return ct

ct1 = calc_count( x1,y1 )
ct2 = calc_count( x2,y2 )

def color_mix( c1 , c2 ):
    cm=np.empty_like(c1)
    for i in [0,1,2]:
        cm[i] = (c1[i]+c2[i])/2.
    return cm

dens1 = ct1 / np.max(ct1)
dens2 = ct2 / np.max(ct2)

ct1_color = np.array([1+0*dens1 , 1-dens1 , 1-dens1  ])
ct2_color = np.array([1-dens2   , 1-dens2 , 1+0*dens2])

col = color_mix( ct1_color , ct2_color )
col = np.transpose( col, axes=(2,1,0))


plt.imshow( col , interpolation='nearest' ,extent=(xmin,xmax,ymin,ymax),origin='lower')
plt.show()

谢谢!我必须在对数空间中绘制我的比例尺,但结果很好。我会在我的问题中发布它,这样你就可以看到了。 - ZSG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接