Я хотел бы сделать диаграмму рассеяния, где каждая точка окрашена в соответствии с пространственной плотностью соседних точек.
Я столкнулся с очень похожим вопросом, в котором показан пример этого с использованием R:
R Точечная диаграмма: цвет символа представляет количество перекрывающихся точек
Какой лучший способ сделать что-то подобное в Python с помощью matplotlib?
python
matplotlib
2964502
источник
источник
Ответы:
В дополнение к предложению @askewchan
hist2d
илиhexbin
в соответствии с ним вы можете использовать тот же метод, который используется в принятом ответе на вопрос, на который вы ссылаетесь.Если вы хотите это сделать:
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, edgecolor='') 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, edgecolor='') plt.show()
источник
plt.colorbar()
, или, если вы предпочитаете быть более точным, сделайтеcax = ax.scatter(...)
и затемfig.colorbar(cax)
. Имейте в виду, что единицы измерения разные. Этот метод оценивает функцию распределения вероятностей для точек, поэтому значения будут между 0 и 1 (и обычно не очень близки к 1). Вы можете преобразовать обратно в что-то более близкое к гистограммам, но это потребует некоторой работы (вам нужно знать параметры,gaussian_kde
рассчитанные на основе данных).Вы можете составить гистограмму:
import numpy as np import matplotlib.pyplot as plt # fake data: a = np.random.normal(size=1000) b = a*3 + np.random.normal(size=1000) plt.hist2d(a, b, (50, 50), cmap=plt.cm.jet) plt.colorbar()
источник
plt.hist2d(…, norm = LogNorm())
(сfrom matplotlib.colors import LogNorm
).Кроме того, если количество точек делает расчет KDE слишком медленным, цвет можно интерполировать в np.histogram2d [Обновить в ответ на комментарии: если вы хотите показать шкалу цвета, используйте plt.scatter () вместо ax.scatter () с последующим автор plt.colorbar ()]:
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm from matplotlib.colors import Normalize from scipy.interpolate import interpn def density_scatter( x , y, ax = None, sort = True, bins = 20, **kwargs ) : """ Scatter plot colored by 2d histogram """ if ax is None : fig , ax = plt.subplots() data , x_e, y_e = np.histogram2d( x, y, bins = bins, density = True ) z = interpn( ( 0.5*(x_e[1:] + x_e[:-1]) , 0.5*(y_e[1:]+y_e[:-1]) ) , data , np.vstack([x,y]).T , method = "splinef2d", bounds_error = False) #To be sure to plot all data z[np.where(np.isnan(z))] = 0.0 # Sort the points by density, so that the densest points are plotted last if sort : idx = z.argsort() x, y, z = x[idx], y[idx], z[idx] ax.scatter( x, y, c=z, **kwargs ) norm = Normalize(vmin = np.min(z), vmax = np.max(z)) cbar = fig.colorbar(cm.ScalarMappable(norm = norm), ax=ax) cbar.ax.set_ylabel('Density') return ax if "__main__" == __name__ : x = np.random.normal(size=100000) y = x * 3 + np.random.normal(size=100000) density_scatter( x, y, bins = [30,30] )
источник
Построение> 100 тыс. Точек данных?
Общепринятый ответ , используя gaussian_kde () займет много времени. На моей машине 100 тысяч строк заняли около 11 минут . Здесь я добавлю два альтернативных метода ( mpl-scatter-density и datashader ) и полученные ответы с тем же набором данных.
Далее я использовал набор тестовых данных из 100 тыс. Строк:
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
Установка
Пример кода
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 секунды:
И масштабирование выглядит неплохо:
2: datashader
pip install "git+https://github.com/nvictus/datashader.git@mpl"
Код (источник dsshow здесь ):
from functools import partial import datashader as ds from datashader.mpl_ext import dsshow import pandas as pd dyn = partial(ds.tf.dynspread, max_px=40, threshold=0.5) def using_datashader(ax, x, y): df = pd.DataFrame(dict(x=x, y=y)) da1 = dsshow(df, ds.Point('x', 'y'), spread_fn=dyn, aspect='auto', ax=ax) plt.colorbar(da1) fig, ax = plt.subplots() using_datashader(ax, x, y) plt.show()
и увеличенное изображение выглядит великолепно!
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='')
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)
5: density_scatter
источник