Контуры Диаграммы Рассеяния В Matplotlib

У меня есть массивный scatterplot (~100,000 точек), который я генерирую в matplotlib. Каждая точка имеет местоположение в этом пространстве x/y, и я хотел бы создать контуры, содержащие определенные процентили от общего числа точек.

есть ли функция в matplotlib, которая сделает это? Я просмотрел contour (), но мне пришлось бы написать свою собственную функцию, чтобы работать таким образом.

спасибо!

2 ответов


в принципе, вы хотите какую-то оценку плотности. Существует несколько способов сделать это:

  1. используйте какую-то 2D-гистограмму (например,matplotlib.pyplot.hist2d или matplotlib.pyplot.hexbin) (вы также можете отобразить результаты в виде контуров-просто используйте numpy.histogram2d а затем контур результирующего массива.)

  2. сделайте оценку плотности ядра (KDE) и контур результатов. KDE по существу является сглаженной гистограммой. Вместо точки, попадающей в определенный ящик, он добавляет вес в соседние ящики (обычно в форме гауссовой колоколообразной кривой).

С помощью 2D-гистограммы проста и легка для понимания, но fundementally дает "блочный" результаты.

есть некоторые морщины, чтобы сделать второй "правильно" (т. е. нет одного правильного способа). Я не буду вдаваться в подробности здесь, но если вы хотите интерпретировать результаты статистически, вам нужно прочитать об этом (особенно о пропускной способности выбор.)

во всяком случае, вот пример различий. Я собираюсь построить каждый из них аналогично, поэтому я не буду использовать контуры, но вы можете так же легко построить 2D-гистограмму или гауссовскую KDE, используя контурный график:

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

np.random.seed(1977)

# Generate 200 correlated x,y points
data = np.random.multivariate_normal([0, 0], [[1, 0.5], [0.5, 3]], 200)
x, y = data.T

nbins = 20

fig, axes = plt.subplots(ncols=2, nrows=2, sharex=True, sharey=True)

axes[0, 0].set_title('Scatterplot')
axes[0, 0].plot(x, y, 'ko')

axes[0, 1].set_title('Hexbin plot')
axes[0, 1].hexbin(x, y, gridsize=nbins)

axes[1, 0].set_title('2D Histogram')
axes[1, 0].hist2d(x, y, bins=nbins)

# Evaluate a gaussian kde on a regular grid of nbins x nbins over data extents
k = kde.gaussian_kde(data.T)
xi, yi = np.mgrid[x.min():x.max():nbins*1j, y.min():y.max():nbins*1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))

axes[1, 1].set_title('Gaussian KDE')
axes[1, 1].pcolormesh(xi, yi, zi.reshape(xi.shape))

fig.tight_layout()
plt.show()

enter image description here

одно предостережение: с очень большим количеством очков,scipy.stats.gaussian_kde станет очень медленной. Это довольно легко, чтобы его ускорить, сделав приближение ... просто в 2D гистограммы и размыть его с помощью фильтра guassian из правый радиус и ковариация. Я могу привести пример, если хочешь.

один нюанс: если вы делаете это в декартовой системе координат, ни один из этих методов применить! Получение оценок плотности на сферической оболочке немного сложнее.


у меня тот же вопрос. Если вы хотите построить контуры, которые содержат некоторую часть точек, вы можете использовать следующий алгоритм:

создать 2d гистограмму

h2, xedges, yedges = np.histogram2d(X, Y, bibs = [30, 30])

h2 теперь 2d-матрица, содержащая целые числа, которые являются количеством точек в некотором прямоугольнике

hravel = np.sort(np.ravel(h2))[-1] #all possible cases for rectangles 
hcumsum = np.sumsum(hravel)

грязный хак,

пусть для каждой точки в h2 2d-матрице задано кумулятивное число точек для прямоугольника, содержащих количество точек, равное или большее, чем мы анализируем в настоящий момент.

hunique = np.unique(hravel)

hsum = np.sum(h2)

for h in hunique:
    h2[h2 == h] = hcumsum[np.argwhere(hravel == h)[-1]]/hsum

Теперь контур графика для h2, это будет контур, который содержит некоторое количество всех точек