Есть ли что-нибудь в matplotlib, которое ведет себя как альфа, но наоборот? - PullRequest
0 голосов
/ 31 января 2019

Хороший способ показать концентрацию точек данных на графике - использовать точечный график с прозрачностью, не равной единице.В результате области с большей концентрацией будут казаться темнее.

# 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

Представьте себеслучай, который мы хотим подчеркнуть на выбросы.Таким образом, ситуация почти полностью изменена: заговор, в котором менее сконцентрированные области являются более смелыми.(Для моего простого примера можно применить хитрость, но представьте себе общий случай, когда распределение точек ранее неизвестно или сложно определить правило прозрачности / веса для цвета.)

Iподумал, есть ли что-нибудь удобное, как alpha, предназначенное специально для этой работы.Хотя приветствуются и другие идеи для выделения выбросов.


ОБНОВЛЕНИЕ: Вот что происходит, когда в одной и той же области разбросано более одной точки данных: enter image description here

Я ищу что-то похожее на картинку ниже, чем больше точка данных, тем менее прозрачен маркер.

enter image description here

Ответы [ 4 ]

0 голосов
/ 31 января 2019

Чтобы ответить на вопрос: Вы можете рассчитать плотность точек, нормализовать ее и закодировать в альфа-канал цветовой карты.

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

Слева - исходное изображение, справа - изображение, где точки с более высокой плотностью имеют меньшую альфа.

Заметьте, однако, что это нежелательно, потому что прозрачные точки высокой плотности неотличимы от низкой плотности.Т.е. на правом изображении это действительно выглядит так, как будто у вас есть дыра в середине вашего дистрибутива.

Очевидно, что решение с цветовой картой, не содержащей цвет фона, намного меньше сбивает с толку читателя.

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

Здесь точки с низкой плотностью по-прежнему подчеркиваются более темным цветом, но в то же время зрителю ясно, что самая высокая плотностьлежит посередине.

0 голосов
/ 31 января 2019

Насколько я знаю, нет "прямого" решения этой довольно интересной проблемы.В качестве обходного пути я предлагаю следующее решение:

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)
0 голосов
/ 31 января 2019

Предполагая, что распределения сосредоточены вокруг определенной точки (например, (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

0 голосов
/ 31 января 2019

Я не знаю, поможет ли это вам, потому что это не совсем то, о чем вы просили, но вы можете просто закрасить точки, значения которых превышают некоторый порог.Например:

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...