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

新手上路,请多包涵

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

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

R Scatter Plot:符号颜色代表重叠点的数量

使用 matplotlib 在 python 中完成类似操作的最佳方法是什么?

原文由 2964502 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

除了 hist2dhexbin 正如@askewchan 所建议的,您还可以使用您链接到的问题中接受的答案所使用的相同方法。

如果你想这样做:

 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()

在此处输入图像描述

原文由 Joe Kington 发布,翻译遵循 CC BY-SA 4.0 许可协议

绘制 >100k 数据点?

公认的答案,使用 gaussian_kde() 会花费很多时间。在我的机器上,10 万行大约需要 11 分钟。在这里,我将添加两种替代方法( mpl-scatter-densitydatashader )并将给定的答案与相同的数据集进行比较。

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

 import matplotlib.pyplot as plt
import numpy as np

# Fake data for testing
x = np.random.normal(size=100000)
y = x * 3 + np.random.normal(size=100000)

输出&计算时间比较

下面是不同方法的比较。

1: mpl-scatter-density

安装

pip install mpl-scatter-density

示例代码

import mpl_scatter_density # adds projection='scatter_density'
from matplotlib.colors import LinearSegmentedColormap

# "Viridis-like" colormap with white background
white_viridis = LinearSegmentedColormap.from_list('white_viridis', [
    (0, '#ffffff'),
    (1e-20, '#440053'),
    (0.2, '#404388'),
    (0.4, '#2a788e'),
    (0.6, '#21a784'),
    (0.8, '#78d151'),
    (1, '#fde624'),
], N=256)

def using_mpl_scatter_density(fig, x, y):
    ax = fig.add_subplot(1, 1, 1, projection='scatter_density')
    density = ax.scatter_density(x, y, cmap=white_viridis)
    fig.colorbar(density, label='Number of points per pixel')

fig = plt.figure()
using_mpl_scatter_density(fig, x, y)
plt.show()

绘制这需要 0.05 秒: 使用 mpl 散射密度

放大看起来很不错: 放大 mpl 散射密度

2: datashader

安装

pip install datashader

代码( dsshow 的源代码和参数列表):


import datashader as ds
from datashader.mpl_ext import dsshow
import pandas as pd

def using_datashader(ax, x, y):

    df = pd.DataFrame(dict(x=x, y=y))
    dsartist = dsshow(
        df,
        ds.Point("x", "y"),
        ds.count(),
        vmin=0,
        vmax=35,
        norm="linear",
        aspect="auto",
        ax=ax,
    )

    plt.colorbar(dsartist)

fig, ax = plt.subplots()
using_datashader(ax, x, y)
plt.show()

  • 绘制这个花了 0.83 秒:

在此处输入图像描述

  • 也有可能通过第三个变量着色。 dsshow 的第三个参数控制着色。在 此处 查看更多示例, 在此处 查看 dsshow 的源代码。

3: scatter_with_gaussian_kde

 def scatter_with_gaussian_kde(ax, x, y):
    # https://stackoverflow.com/a/20107592/3015186
    # Answer by Joel Kington

    xy = np.vstack([x, y])
    z = gaussian_kde(xy)(xy)

    ax.scatter(x, y, c=z, s=100, edgecolor='')

  • 画这个花了 11 分钟: scatter_with_gaussian_kde

4: using_hist2d

 import matplotlib.pyplot as plt
def using_hist2d(ax, x, y, bins=(50, 50)):
    # https://stackoverflow.com/a/20105673/3015186
    # Answer by askewchan
    ax.hist2d(x, y, bins, cmap=plt.cm.jet)

  • 绘制这个 bins=(50,50) 花费了 0.021 秒: 使用_hist2d_50
  • 绘制这个 bins=(1000,1000) 花费了 0.173 秒: 使用_hist2d_1000
  • 缺点:放大的数据看起来不如 mpl-scatter-density 或数据着色器。您还必须自己确定垃圾箱的数量。

放大 hist2d 1000bins

5: density_scatter

  • 代码与 Guillaume回答 相同。
  • 使用 bins=(50,50) 绘制此图需要 0.073 秒: density_scatter_50bins
  • 使用 bins=(1000,1000) 绘制此图需要 0.368 秒: density_scatter_1000bins

原文由 np8 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题