matplotlib中是否有任何行为类似于alpha但被反转了?

时间:2019-01-31 09:20:20

标签: python matplotlib

在图中显示数据点集中度的一个好方法是使用具有非单位透明度的散点图。结果,浓度较高的区域将显得更暗。

# this is synthetic example
N = 10000       # a very very large number
x = np.random.normal(0, 1, N)
y = np.random.normal(0, 1, N)
plt.scatter(x, y, marker='.', alpha=0.1)  # an area full of dots, darker wherever the number of dots is more

它给出了这样的内容:

enter image description here

想象一下我们要强调的异常情况。因此,情况几乎被扭转:情节较集中的区域变粗了。 (在我的简单示例中可能有一个技巧,但可以想象一个普遍的情况,即事先不知道点的分布,或者很难定义透明度/颜色权重的规则。)

我在想是否有专门用于这项工作的与alpha一样方便的东西。尽管也欢迎其他强调离群值的想法。


更新:当在同一区域上散布了多个数据点时,会发生以下情况: enter image description here

我正在寻找下面的图片,数据点越多,标记的透明度越低。

enter image description here

4 个答案:

答案 0 :(得分:2)

据我所知,还没有“直接”解决方案来解决这个非常有趣的问题。作为解决方法,我提出了以下解决方案:

N = 10000       # a very very large number
x = np.random.normal(0, 1, N)
y = np.random.normal(0, 1, N)
fig = plt.figure()  # create figure directly to be able to extract the bg color
ax = fig.gca()
ax.scatter(x, y, marker='.')  # plot all markers without alpha
bgcolor = ax.get_facecolor()  # extract current background color
# plot with alpha, "overwriting" dense points
ax.scatter(x, y, marker='.', color=bgcolor, alpha=0.2)

这将绘制没有透明度的所有点,然后再次以一定透明度绘制所有点,“覆盖”密度最高的那些点。将alpha的值设置为其他更高的值将更加强调离群值,反之亦然。

当然,第二个散点图的颜色需要调整为您的背景色。在我的示例中,这是通过提取背景色并将其设置为新的散点图的颜色来完成的。

此解决方案与分发类型无关。它仅取决于点的密度。但是它产生的点数是原来的两倍,因此渲染时间可能会稍长一些。


再现问题中的编辑,我的解决方案正好显示了所需的行为。最左边的点是一个点,是最暗的,最右边的点是由三个点组成,是最浅的颜色。

x = [0, 1, 1, 2, 2, 2]
y = [0, 0, 0, 0, 0, 0]
fig = plt.figure()  # create figure directly to be able to extract the bg color
ax = fig.gca()
ax.scatter(x, y, marker='.', s=10000)  # plot all markers without alpha
bgcolor = ax.get_facecolor()  # extract current background color
# plot with alpha, "overwriting" dense points
ax.scatter(x, y, marker='.', color=bgcolor, alpha=0.2, s=10000)

答案 1 :(得分:1)

假设分布以某个特定点为中心(例如,本例中为(0,0)),我将使用以下方式:

import numpy as np
import matplotlib.pyplot as plt

N = 500
# 0 mean, 0.2 std
x = np.random.normal(0,0.2,N)
y = np.random.normal(0,0.2,N)

# calculate the distance to (0, 0).
color = np.sqrt((x-0)**2 + (y-0)**2)

plt.scatter(x , y, c=color, cmap='plasma', alpha=0.7)
plt.show()

结果:

enter image description here

答案 2 :(得分:1)

要回答这个问题:您可以计算点的密度,对其进行归一化并在色图的alpha通道中对其进行编码。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

# this is synthetic example
N = 10000       # a very very large number
x = np.random.normal(0, 1, N)
y = np.random.normal(0, 1, N)


fig, (ax,ax2) = plt.subplots(ncols=2, figsize=(8,5))
ax.scatter(x, y, marker='.', alpha=0.1)

values = np.vstack([x,y])
kernel = stats.gaussian_kde(values)
weights = kernel(values)
weights = weights/weights.max()

cols = plt.cm.Blues([0.8, 0.5])
cols[:,3] = [1., 0.005]
cmap = LinearSegmentedColormap.from_list("", cols)

ax2.scatter(x, y, c=weights, s = 1, marker='.', cmap=cmap)

plt.show()

enter image description here

左图是原始图像,右图是密度较高的点的alpha值较低的图像。

但是,这是不希望的,因为高密度透明点与低密度是无法区分的。即在正确的图像中,看起来好像您的分布中间有一个洞。

很显然,使用不包含背景颜色的色图的解决方案,对读者而言,混乱程度要小得多。

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

# this is synthetic example
N = 10000       # a very very large number
x = np.random.normal(0, 1, N)
y = np.random.normal(0, 1, N)

fig, ax = plt.subplots(figsize=(5,5))

values = np.vstack([x,y])
kernel = stats.gaussian_kde(values)
weights = kernel(values)
weights = weights/weights.max()

ax.scatter(x, y, c = weights, s=9, edgecolor="none", marker='.', cmap="magma")

plt.show()

enter image description here

在这里,低密度点仍然通过深色来强调,但是同时,观众可以清楚地看到最高密度位于中间。

答案 3 :(得分:0)

我不知道它是否对您有帮助,因为它并不是您真正要求的,但是您可以简单地为色点着色,该色点的值大于某个阈值。例如:

import matplotlib.pyplot as plt

num = 100
threshold = 80

x = np.linspace(0, 100, num=num)
y = np.random.normal(size=num)*45

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(x[np.abs(y) < threshold], y[np.abs(y) < threshold], color="#00FFAA")
ax.scatter(x[np.abs(y) >= threshold], y[np.abs(y) >= threshold], color="#AA00FF")
plt.show()