matplotlib 中重叠点散点图的可视化

问题描述 投票:0回答:4

我必须在 matplotlib 的散点图中表示大约 30,000 个点。这些点属于两个不同的类,所以我想用不同的颜色来描绘它们。

我成功这样做了,但是有一个问题。这些点在许多区域重叠,我最后描述的类将在另一个类之上可视化,将其隐藏。此外,散点图无法显示每个区域中有多少个点。 我也尝试过用 histogram2d 和 imshow 制作二维直方图,但很难以清晰的方式显示属于这两个类的点。

你能建议一种方法,既能明确班级的分布,又能明确点的集中度吗?

编辑:更清楚地说,这是 链接到我的数据文件,格式为“x,y,class”

python matplotlib plot visualization scatter-plot
4个回答
50
投票

一种方法是将数据绘制为具有低 alpha 散点图,这样您就可以看到各个点以及粗略的密度测量。 (这样做的缺点是该方法可以显示的重叠范围有限——即最大密度约为 1/alpha。)

这是一个例子:

enter image description here

正如您可以想象的那样,由于可以表达的重叠范围有限,因此在各个点的可见性和重叠量的表达(以及标记、绘图等的大小)之间存在权衡。

import numpy as np
import matplotlib.pyplot as plt

N = 10000
mean = [0, 0]
cov = [[2, 2], [0, 2]]
x,y = np.random.multivariate_normal(mean, cov, N).T

plt.scatter(x, y, s=70, alpha=0.03)
plt.ylim((-5, 5))
plt.xlim((-5, 5))
plt.show()

(我假设这里你的意思是 30e3 点,而不是 30e6。对于 30e6,我认为某种类型的平均密度图是必要的。)


41
投票

您还可以通过首先计算散点分布的核密度估计,然后使用密度值指定散点的每个点的颜色来对点进行着色。要修改前面示例中的代码:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde as kde
from matplotlib.colors import Normalize
from matplotlib import cm

N = 10000
mean = [0,0]
cov = [[2,2],[0,2]]

samples = np.random.multivariate_normal(mean,cov,N).T
densObj = kde( samples )

def makeColours( vals ):
    colours = np.zeros( (len(vals),3) )
    norm = Normalize( vmin=vals.min(), vmax=vals.max() )

    #Can put any colormap you like here.
    colours = [cm.ScalarMappable( norm=norm, cmap='jet').to_rgba( val ) for val in vals]

    return colours

 colours = makeColours( densObj.evaluate( samples ) )

 plt.scatter( samples[0], samples[1], color=colours )
 plt.show()

不久前,当我注意到 scatter 函数的文档时,我学会了这个技巧 --

c : color or sequence of color, optional, default : 'b'

c
可以是单个颜色格式字符串,或者长度为
N
的颜色规范序列,或者使用通过 kwargs 指定的
N
cmap
映射到颜色的
norm
数字序列(见下文)。请注意,
c
不应该是单个数字 RGB 或 RGBA 序列,因为它与要进行颜色映射的值数组无法区分。
c
可以是二维数组,其中行是 RGB 或 RGBA,但是,包括单行为所有点指定相同颜色的情况。


4
投票

我的答案可能无法完美回答您的问题,但是,我也尝试绘制重叠点,但我的答案完全重叠。因此,我想出了这个函数来抵消相同的点。

import numpy as np

def dodge_points(points, component_index, offset):
    """Dodge every point by a multiplicative offset (multiplier is based on frequency of appearance)

    Args:
        points (array-like (2D)): Array containing the points
        component_index (int): Index / column on which the offset will be applied 
        offset (float): Offset amount. Effective offset for each point is `index of appearance` * offset

    Returns:
        array-like (2D): Dodged points
    """

    # Extract uniques points so we can map an offset for each
    uniques, inv, counts = np.unique(
        points, return_inverse=True, return_counts=True, axis=0
    )

    for i, num_identical in enumerate(counts):
        # Prepare dodge values
        dodge_values = np.array([offset * i for i in range(num_identical)])
        # Find where the dodge values must be applied, in order
        points_loc = np.where(inv == i)[0]
        #Apply the dodge values
        points[points_loc, component_index] += dodge_values

    return points

这是之前和之后的示例。

之前:

之后:

此方法仅适用于完全重叠的点(或者如果您愿意以

np.unique
找到匹配点的方式对点进行舍入)。


0
投票

使用透明度/alpha,如这个答案中所建议的,对于拥挤问题的情况非常有帮助。但是,如果您有多个数据类,您仍然可能会遇到后面绘制的类掩盖了前面的类的问题,特别是如果某些类比其他类具有更多的数据点。

这个答案使用热图来显示密度,当您想要显示单个类的密度时,这非常有用,但不能直接适应您有多个重叠类并希望所有类都可见的情况。

我有时发现在这种情况下有用的一种方法是随机化绘图顺序,而不是按顺序绘制类。这可以与透明度结合起来。

例如修改tom10的答案中给出的例子:

import numpy as np
import matplotlib.pyplot as plt

N0 = 2000
x0 = np.random.normal(0,2,N0)
y0 = np.random.normal(0,0.2,N0) + 0.25/(x0**2+0.25)

plt.scatter(x0, y0, s=70, alpha=0.03,c="r")

N1 = 10000
mean = [0, 0]
cov = [[2, 2], [0, 2]]
x1,y1 = np.random.multivariate_normal(mean, cov, N1).T

plt.scatter(x1, y1, s=70, alpha=0.03,c="b")
plt.ylim((-5, 5))
plt.xlim((-5, 5))
plt.show()

结果:

看一下该图,红点似乎分布在 y = 0 线附近。

但是如果我们随机化绘图顺序:

x = np.concatenate((x0,x1))
y = np.concatenate((y0,y1))
cols = np.concatenate((np.tile("r",len(x0)),np.tile("b",len(x1))))

rng = np.random.default_rng()
neworder=rng.permutation(len(x))

x_shuffled = x[neworder]
y_shuffled = y[neworder]
cols_shuffled = cols[neworder]

plt.ylim((-5, 5))
plt.xlim((-5, 5))
plt.show()

我们得到这个:

现在可以更容易地看到,在 x = 0 附近,红点显着偏离我们在只能看到该分布的边缘时猜测的 y=0 关系。

我们可以通过对点进行分箱(例如在六角形或方形网格上)然后根据每个箱的类分布和数据点数量设置每个箱的颜色和 alpha 来实现类似的结果。但我喜欢随机顺序方法,因为它技术含量较低,并且减少了我需要记住的方法数量。

© www.soinside.com 2019 - 2024. All rights reserved.