边缘效应密度 2D 图与 KDE [英] Edge effects Density 2D plot with KDE
问题描述
我正在绘制一个简单的二维密度图,使用
我已经尝试了
可以看出,所得密度图的变化并非微不足道.我个人认为镜像数据KDE可以更好地表示实际密度.
将 numpy 导入为 np来自 scipy 导入统计导入matplotlib.pyplot作为pltdef in_box(塔,bounding_box):返回np.logical_and(np.logical_and(bounding_box [0]< =塔[:,0],塔[:,0]< = bounding_box [1]),np.logical_and(bounding_box[2] <= Towers[:, 1],塔 [:, 1] <= bounding_box[3]))def dataMirror(塔,bounding_box,perc = .1):# 选择边界框内的塔i = in_box(塔,bounding_box)# 镜像点points_center = 塔 [i, :]points_left = np.copy(points_center)points_left[:, 0] = bounding_box[0] - (points_left[:, 0] - bounding_box[0])points_right = np.copy(points_center)points_right[:, 0] = bounding_box[1] + (bounding_box[1] - points_right[:, 0])points_down = np.copy(points_center)points_down[:, 1] = bounding_box[2] - (points_down[:, 1] - bounding_box[2])points_up = np.copy(points_center)points_up [:, 1] = bounding_box [3] +(bounding_box [3]-points_up [:, 1])点 = np.append(points_center,np.append(np.append(points_left,点数正确,轴=0),np.append(points_down,点数上升,轴=0),轴=0),轴=0)# 将镜像框架修剪到perc"垫内xr,yr = np.ptp(towers.T [0])* perc,np.ptp(towers.T [1])* percxmin, xmax = bounding_box[0] - xr, bounding_box[1] + xrymin, ymax = bounding_box[2] - yr, bounding_box[3] + yrmsk =(points [:, 0]> xmin)&(points[:, 0] < xmax) &\(points[:, 1] > ymin) &(点[:, 1] < ymax)点数 = 点数[msk]返回点.Tdef KDEplot(xmin,xmax,ymin,ymax,值):#高斯KDE.内核= stats.gaussian_kde(值,bw_method = .2)#网格密度(点数).gd_c = complex(0,50)#定义x,y网格.x_grid, y_grid = np.mgrid[xmin:xmax:gd_c, ymin:ymax:gd_c]职位= np.vstack([x_grid.ravel(),y_grid.ravel()])#评估内核在网格位置中的位置.k_pos = 内核(位置)ext_range = [xmin,xmax,ymin,ymax]kde = np.reshape(k_pos.T,x_grid.shape)plt.imshow(np.rot90(kde), cmap=plt.get_cmap('RdYlBu_r'), extent=ext_range)x_data = np.random.uniform(1., 2000., 1000)y_data = np.random.uniform(1., 2000., 1000)xmin, xmax = np.min(x_data), np.max(x_data)ymin,ymax = np.min(y_data),np.max(y_data)值 = np.vstack([x_data, y_data])#绘制非镜像数据plt.subplot(121)KDEplot(xmin, xmax, ymin, ymax, values)plt.scatter(*values, s=3, c='k')plt.xlim(xmin,xmax)plt.ylim(ymin, ymax)# 绘制镜像数据bounding_box =(xmin,xmax,ymin,ymax)values = dataMirror(values.T, bounding_box)plt.subplot(122)KDEplot(xmin, xmax, ymin, ymax, values)plt.scatter(*values, s=3, c='k')plt.xlim(xmin,xmax)plt.ylim(ymin, ymax)plt.show()
I'm plotting a simple 2D density map obtained with scipy.stats.gaussian_kde. There is always a plotting artifact towards the edges where the density appears to be lower:
I've tried every interpolation method in imshow() and none seems to be able to get rid of it. Is there a proper way to handle this?
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
x_data = np.random.uniform(1., 2000., 1000)
y_data = np.random.uniform(1., 2000., 1000)
xmin, xmax = np.min(x_data), np.max(x_data)
ymin, ymax = np.min(y_data), np.max(y_data)
values = np.vstack([x_data, y_data])
# Gaussian KDE.
kernel = stats.gaussian_kde(values, bw_method=.2)
# Grid density (number of points).
gd_c = complex(0, 50)
# Define x,y grid.
x_grid, y_grid = np.mgrid[xmin:xmax:gd_c, ymin:ymax:gd_c]
positions = np.vstack([x_grid.ravel(), y_grid.ravel()])
# Evaluate kernel in grid positions.
k_pos = kernel(positions)
ext_range = [xmin, xmax, ymin, ymax]
kde = np.reshape(k_pos.T, x_grid.shape)
im = plt.imshow(np.rot90(kde), cmap=plt.get_cmap('RdYlBu_r'), extent=ext_range)
plt.show()
After a while I found a way to address this issue applying a neat trick explained by Flabetvibes in this excellent answer.
I use the code shown there to mirror the data as shown in the first figure of the mentioned answer. The only modification I introduced is to trim the mirrored data to a perc
padding (I set it to 10% by default) so as not to carry around a lot of unnecessary values.
The result is shown here, original non-mirrored data to the left, and mirrored data to the right:
As can be seen, the changes in the resulting density map are not trivial. I personally believe the mirrored-data KDE represents the actual density better.
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
def in_box(towers, bounding_box):
return np.logical_and(np.logical_and(bounding_box[0] <= towers[:, 0],
towers[:, 0] <= bounding_box[1]),
np.logical_and(bounding_box[2] <= towers[:, 1],
towers[:, 1] <= bounding_box[3]))
def dataMirror(towers, bounding_box, perc=.1):
# Select towers inside the bounding box
i = in_box(towers, bounding_box)
# Mirror points
points_center = towers[i, :]
points_left = np.copy(points_center)
points_left[:, 0] = bounding_box[0] - (points_left[:, 0] - bounding_box[0])
points_right = np.copy(points_center)
points_right[:, 0] = bounding_box[1] + (bounding_box[1] - points_right[:, 0])
points_down = np.copy(points_center)
points_down[:, 1] = bounding_box[2] - (points_down[:, 1] - bounding_box[2])
points_up = np.copy(points_center)
points_up[:, 1] = bounding_box[3] + (bounding_box[3] - points_up[:, 1])
points = np.append(points_center,
np.append(np.append(points_left,
points_right,
axis=0),
np.append(points_down,
points_up,
axis=0),
axis=0),
axis=0)
# Trim mirrored frame to withtin a 'perc' pad
xr, yr = np.ptp(towers.T[0]) * perc, np.ptp(towers.T[1]) * perc
xmin, xmax = bounding_box[0] - xr, bounding_box[1] + xr
ymin, ymax = bounding_box[2] - yr, bounding_box[3] + yr
msk = (points[:, 0] > xmin) & (points[:, 0] < xmax) &\
(points[:, 1] > ymin) & (points[:, 1] < ymax)
points = points[msk]
return points.T
def KDEplot(xmin, xmax, ymin, ymax, values):
# Gaussian KDE.
kernel = stats.gaussian_kde(values, bw_method=.2)
# Grid density (number of points).
gd_c = complex(0, 50)
# Define x,y grid.
x_grid, y_grid = np.mgrid[xmin:xmax:gd_c, ymin:ymax:gd_c]
positions = np.vstack([x_grid.ravel(), y_grid.ravel()])
# Evaluate kernel in grid positions.
k_pos = kernel(positions)
ext_range = [xmin, xmax, ymin, ymax]
kde = np.reshape(k_pos.T, x_grid.shape)
plt.imshow(np.rot90(kde), cmap=plt.get_cmap('RdYlBu_r'), extent=ext_range)
x_data = np.random.uniform(1., 2000., 1000)
y_data = np.random.uniform(1., 2000., 1000)
xmin, xmax = np.min(x_data), np.max(x_data)
ymin, ymax = np.min(y_data), np.max(y_data)
values = np.vstack([x_data, y_data])
# Plot non-mirrored data
plt.subplot(121)
KDEplot(xmin, xmax, ymin, ymax, values)
plt.scatter(*values, s=3, c='k')
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
# Plot mirrored data
bounding_box = (xmin, xmax, ymin, ymax)
values = dataMirror(values.T, bounding_box)
plt.subplot(122)
KDEplot(xmin, xmax, ymin, ymax, values)
plt.scatter(*values, s=3, c='k')
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
plt.show()
这篇关于边缘效应密度 2D 图与 KDE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!