Python 如何在matplotlib中绘制按密度着色的散点图?

Python 如何在matplotlib中绘制按密度着色的散点图?,python,matplotlib,Python,Matplotlib,我想做一个散点图,其中每个点都由附近点的空间密度着色 我遇到了一个非常类似的问题,它显示了一个使用R的例子: 使用matplotlib在python中实现类似功能的最佳方法是什么?您可以制作一个直方图: import numpy as np import matplotlib.pyplot as plt # fake data: a = np.random.normal(size=1000) b = a*3 + np.random.normal(size=1000) plt.hist2d(

我想做一个散点图,其中每个点都由附近点的空间密度着色

我遇到了一个非常类似的问题,它显示了一个使用R的例子:


使用matplotlib在python中实现类似功能的最佳方法是什么?

您可以制作一个直方图:

import numpy as np
import matplotlib.pyplot as plt

# fake data:
a = np.random.normal(size=1000)
b = a*3 + np.random.normal(size=1000)

plt.hist2d(a, b, (50, 50), cmap=plt.cm.jet)
plt.colorbar()

除了@askewchan建议的
hist2d
hexbin
之外,您还可以使用链接到的问题中的公认答案所使用的相同方法

如果您想这样做:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde

# Generate fake data
x = np.random.normal(size=1000)
y = x * 3 + np.random.normal(size=1000)

# Calculate the point density
xy = np.vstack([x,y])
z = gaussian_kde(xy)(xy)

fig, ax = plt.subplots()
ax.scatter(x, y, c=z, s=100)
plt.show()

如果希望按密度顺序打印点,以便最密集的点始终位于顶部(类似于链接的示例),只需按z值对其排序即可。我还将在这里使用更小的标记大小,因为它看起来更好一些:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde

# Generate fake data
x = np.random.normal(size=1000)
y = x * 3 + np.random.normal(size=1000)

# Calculate the point density
xy = np.vstack([x,y])
z = gaussian_kde(xy)(xy)

# Sort the points by density, so that the densest points are plotted last
idx = z.argsort()
x, y, z = x[idx], y[idx], z[idx]

fig, ax = plt.subplots()
ax.scatter(x, y, c=z, s=50)
plt.show()

此外,如果点数使KDE计算太慢,可以在np.historogram2d中插值颜色[根据注释更新:如果希望显示颜色栏,请使用plt.scatter()而不是ax.scatter(),后跟plt.colorbar()]:

绘图>100k数据点? 使用,将花费很多时间。在我的机器上,10万行花了大约11分钟。在这里,我将添加两个可选方法(和),并将给定的答案与相同的数据集进行比较

在下面,我使用了一个100k行的测试数据集:

导入matplotlib.pyplot作为plt
将numpy作为np导入
#用于测试的假数据
x=np.随机.正常(尺寸=100000)
y=x*3+np.随机.正常(尺寸=100000)
输出和计算时间比较 下面是不同方法的比较

1:mpl散射密度
安装

pip install mpl-scatter-density
示例代码

pip install mpl-scatter-density
import mpl_scatter_density#添加投影='scatter_density'
从matplotlib.colors导入LinearSegmentedColormap
#白色背景的“类绿色”彩色地图
white_viridis=LinearSegmentedColormap。从_列表(“white_viridis”)[
(0,#ffffff'),
(1e-20,“440053”),
(0.2, '#404388'),
(0.4,#2a788e'),
(0.6,#21a784'),
(0.8,#78d151'),
(1,“fde624”),
],N=256)
使用散射密度的def(图x、y):
ax=图添加子图(1,1,1,投影=“散射密度”)
密度=最大散射密度(x,y,cmap=白色绿色)
图颜色条(密度,标签='每像素点数')
图=plt.图()
使用散射密度(图,x,y)
plt.show()
绘制此图花费了0.05秒:

放大效果看起来相当不错:

2:datashader
  • 这是一个有趣的项目。然而,截至2020年9月,该公司仍将继续运营。我从以下克隆安装了mpl分支:
代码(dsshow的源代码):

从functools导入部分
将datashader作为ds导入
从datashader.mpl\u ext导入dsshow
作为pd进口熊猫
dyn=部分(ds.tf.dynspread,max_px=40,阈值=0.5)
使用_数据着色器(ax、x、y)定义:
df=pd.DataFrame(dict(x=x,y=y))
da1=dsshow(df,ds.点('x','y'),排列=dyn,纵横比=auto',ax=ax)
打印颜色条(da1)
图,ax=plt.子批次()
使用_数据着色器(ax、x、y)
plt.show()
  • 绘制此图需要0.83秒:

放大后的图像看起来很棒

3:使用高斯kde进行散射
def scatter_和_gaussian_kde(ax,x,y):
# https://stackoverflow.com/a/20107592/3015186
#乔尔·金顿的回答
xy=np.vstack([x,y])
z=高斯分布(xy)(xy)
最大散射(x,y,c=z,s=100,边缘颜色=“”)
  • 画这个花了11分钟:
4:使用\u hist2d
导入matplotlib.pyplot作为plt
使用_hist2d(ax、x、y、bin=(50、50))定义:
# https://stackoverflow.com/a/20105673/3015186
#阿斯克尚的回答
ax.hist2d(x,y,bin,cmap=plt.cm.jet)
  • 绘制此箱子需要0.021 s=(50,50):
  • 绘制此箱子需要0.173秒=(10001000):
  • 缺点:放大的数据看起来不像mpl散射密度或数据阴影中的数据那样好。此外,您还必须自己确定垃圾箱的数量

5:密度分布
  • 代码如by中所示
  • 使用bins=(50,50)绘制此图需要0.073 s:
  • 使用bins=(10001000)绘制此图需要0.368 s:

嗨!人们一直对你投反对票,可能是因为你没有重写问题或提供任何背景,也没有表现出任何自己做这件事的企图。考虑编辑这个问题是自给自足的(不仅仅是一个链接),对于未来的问题,请在发布之前做一些尝试。聪明的,尤其是在“最密集的”上面:)@ LeZek -醚调用<代码> PLT.ClulBar()/代码>,或者如果你更喜欢显式的话,做<代码> CAX= Ax.Dead(…)<代码>,然后<代码>图Clor Clar。(cax)。请注意单位是不同的。此方法估计点的概率分布函数,因此值将介于0和1之间(通常不会非常接近1)。您可以转换回更接近直方图计数的值,但这需要一些工作(您需要知道从数据中估计的参数。
gaussian_kde
)。为什么用(xy)调用两次gaussian内核?@ArjanGroen第一次调用创建一个新的gaussian_kde对象,第二次调用对点集上估计的pdf进行求值(调用求值方法的快捷方式)。在较新的matplotlib版本中,使用此代码段可能会导致错误
ValueError:Expected 2D array,Get 1
。修复方法是将
edgecolor='
更改为
edgecolor=None
。这是一个很好的提示,谢谢。我正在绘制100k点,而gaussian_kde的速度非常慢。警告,我注意到在某些情况下his生成NaN,因为“bounds_error=False”是静默的。c设置为NaN的点不会绘制。这不是gaussian_kde的问题。非常感谢您的回答。U
pip install "git+https://github.com/nvictus/datashader.git@mpl"