gre*_*eye 172 python matplotlib heatmap histogram2d
我有一组X,Y数据点(大约10k),很容易绘制为散点图,但我想表示为热图.
我查看了MatPlotLib中的示例,他们似乎都已经开始使用热图单元格值来生成图像.
有没有一种方法可以将一堆x,y,所有不同的,转换为热图(其中x,y频率较高的区域会变得"温暖")?
pto*_*ato 172
如果你不想要六边形,你可以使用numpy的histogram2d功能:
import numpy as np
import numpy.random
import matplotlib.pyplot as plt
# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)
heatmap, xedges, yedges = np.histogram2d(x, y, bins=50)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
plt.clf()
plt.imshow(heatmap.T, extent=extent, origin='lower')
plt.show()
Run Code Online (Sandbox Code Playgroud)
这使得50x50热图.如果你想要512x384,你可以bins=(512, 384)拨打电话histogram2d.
例: 
dou*_*oug 105
在Matplotlib词典中,我想你想要一个hexbin情节.
如果您不熟悉这种类型的绘图,它只是一个双变量直方图,其中xy平面由规则的六边形网格进行镶嵌.
因此,从直方图中,您可以只计算每个六边形中的点数,将绘图区域离散为一组窗口,将每个点分配给其中一个窗口; 最后,将窗口映射到一个颜色数组,你有一个hexbin图.
虽然不常用于例如圆形或正方形,但六边形是分箱容器几何形状的更好选择是直观的:
六边形具有最近邻对称性(例如,方形边框不具有,例如,从正方形边界上的点到该正方形内部的点的距离不是到处相等)并且
六边形是最高的n多边形,可以进行常规的平面镶嵌(也就是说,你可以安全地用六角形瓷砖重新塑造你的厨房地板,因为当你完成时你不会在瓷砖之间留下任何空隙 - 不适用于所有其他更高的n,n> = 7,多边形).
(Matplotlib使用术语hexbin情节;所以做(据我所知)所有的绘图库的[R ;还有我不知道这是否是这种类型的地块普遍接受的术语,但我怀疑这是有可能因为hexbin短对于六边形分级,这是描述准备显示数据的必要步骤.)
from matplotlib import pyplot as PLT
from matplotlib import cm as CM
from matplotlib import mlab as ML
import numpy as NP
n = 1e5
x = y = NP.linspace(-5, 5, 100)
X, Y = NP.meshgrid(x, y)
Z1 = ML.bivariate_normal(X, Y, 2, 2, 0, 0)
Z2 = ML.bivariate_normal(X, Y, 4, 1, 1, 1)
ZD = Z2 - Z1
x = X.ravel()
y = Y.ravel()
z = ZD.ravel()
gridsize=30
PLT.subplot(111)
# if 'bins=None', then color of each hexagon corresponds directly to its count
# 'C' is optional--it maps values to x-y coordinates; if 'C' is None (default) then
# the result is a pure 2D histogram
PLT.hexbin(x, y, C=z, gridsize=gridsize, cmap=CM.jet, bins=None)
PLT.axis([x.min(), x.max(), y.min(), y.max()])
cb = PLT.colorbar()
cb.set_label('mean value')
PLT.show()
Run Code Online (Sandbox Code Playgroud)

Ale*_*dro 30
我不想使用np.hist2d,它通常会产生非常难看的直方图,我想回收py-sphviewer,这是一个使用自适应平滑内核渲染粒子模拟的python包,可以从pip轻松安装(参见网页文档).请考虑以下代码,该代码基于以下示例:
import numpy as np
import numpy.random
import matplotlib.pyplot as plt
import sphviewer as sph
def myplot(x, y, nb=32, xsize=500, ysize=500):
xmin = np.min(x)
xmax = np.max(x)
ymin = np.min(y)
ymax = np.max(y)
x0 = (xmin+xmax)/2.
y0 = (ymin+ymax)/2.
pos = np.zeros([3, len(x)])
pos[0,:] = x
pos[1,:] = y
w = np.ones(len(x))
P = sph.Particles(pos, w, nb=nb)
S = sph.Scene(P)
S.update_camera(r='infinity', x=x0, y=y0, z=0,
xsize=xsize, ysize=ysize)
R = sph.Render(S)
R.set_logscale()
img = R.get_image()
extent = R.get_extent()
for i, j in zip(xrange(4), [x0,x0,y0,y0]):
extent[i] += j
print extent
return img, extent
fig = plt.figure(1, figsize=(10,10))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)
#Plotting a regular scatter plot
ax1.plot(x,y,'k.', markersize=5)
ax1.set_xlim(-3,3)
ax1.set_ylim(-3,3)
heatmap_16, extent_16 = myplot(x,y, nb=16)
heatmap_32, extent_32 = myplot(x,y, nb=32)
heatmap_64, extent_64 = myplot(x,y, nb=64)
ax2.imshow(heatmap_16, extent=extent_16, origin='lower', aspect='auto')
ax2.set_title("Smoothing over 16 neighbors")
ax3.imshow(heatmap_32, extent=extent_32, origin='lower', aspect='auto')
ax3.set_title("Smoothing over 32 neighbors")
#Make the heatmap using a smoothing over 64 neighbors
ax4.imshow(heatmap_64, extent=extent_64, origin='lower', aspect='auto')
ax4.set_title("Smoothing over 64 neighbors")
plt.show()
Run Code Online (Sandbox Code Playgroud)
产生以下图像:
如您所见,图像看起来非常好,我们能够在其上识别不同的子结构.这些图像被构造为扩展给定权重,用于某个域内的每个点,由平滑长度定义,而平滑长度又由距离较近的nb邻居的距离给出(我为示例选择了16,32和64).因此,与较低密度区域相比,较高密度区域通常分布在较小区域上.
函数myplot只是一个非常简单的函数,我写的是为了给x-y数据提供py-sphviewer来做魔术.
Jur*_*rgy 28
编辑:为了更好地近似亚历杭德罗的答案,请参见下文.
我知道这是一个老问题,但想添加一些亚历杭德罗的anwser:如果你想要一个漂亮平滑的图像,而无需使用PY-sphviewer您可以改用np.histogram2d和应用高斯滤波器(从scipy.ndimage.filters)的热图:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.ndimage.filters import gaussian_filter
def myplot(x, y, s, bins=1000):
heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
heatmap = gaussian_filter(heatmap, sigma=s)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
return heatmap.T, extent
fig, axs = plt.subplots(2, 2)
# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)
sigmas = [0, 16, 32, 64]
for ax, s in zip(axs.flatten(), sigmas):
if s == 0:
ax.plot(x, y, 'k.', markersize=5)
ax.set_title("Scatter plot")
else:
img, extent = myplot(x, y, s)
ax.imshow(img, extent=extent, origin='lower', cmap=cm.jet)
ax.set_title("Smoothing with $\sigma$ = %d" % s)
plt.show()
Run Code Online (Sandbox Code Playgroud)
生产:
对于Agape Gal'lo,散点图和s = 16在彼此的顶部绘制(点击查看更好的视图):
我注意到我的高斯滤波器方法和亚历杭德罗方法的一个不同之处在于他的方法显示出比我的更好的局部结构.因此,我在像素级实现了一个简单的最近邻法.该方法针对每个像素计算n数据中最近点的距离的倒数和.这种方法的分辨率很高,计算成本很高,而且我认为这种方法更快,所以如果你有任何改进,请告诉我.无论如何,这是代码:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
def data_coord2view_coord(p, vlen, pmin, pmax):
dp = pmax - pmin
dv = (p - pmin) / dp * vlen
return dv
def nearest_neighbours(xs, ys, reso, n_neighbours):
im = np.zeros([reso, reso])
extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]
xv = data_coord2view_coord(xs, reso, extent[0], extent[1])
yv = data_coord2view_coord(ys, reso, extent[2], extent[3])
for x in range(reso):
for y in range(reso):
xp = (xv - x)
yp = (yv - y)
d = np.sqrt(xp**2 + yp**2)
im[y][x] = 1 / np.sum(d[np.argpartition(d.ravel(), n_neighbours)[:n_neighbours]])
return im, extent
n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)
resolution = 250
fig, axes = plt.subplots(2, 2)
for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 64]):
if neighbours == 0:
ax.plot(xs, ys, 'k.', markersize=2)
ax.set_aspect('equal')
ax.set_title("Scatter Plot")
else:
im, extent = nearest_neighbours(xs, ys, resolution, neighbours)
ax.imshow(im, origin='lower', extent=extent, cmap=cm.jet)
ax.set_title("Smoothing over %d neighbours" % neighbours)
ax.set_xlim(extent[0], extent[1])
ax.set_ylim(extent[2], extent[3])
plt.show()
Run Code Online (Sandbox Code Playgroud)
结果:
Pit*_*kul 27
如果您使用的是1.2.x.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.randn(100000)
y = np.random.randn(100000)
plt.hist2d(x,y,bins=100)
plt.show()
Run Code Online (Sandbox Code Playgroud)

wor*_*ise 15
Seaborn现在有了jointplot功能,它应该可以在这里很好地工作:
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)
sns.jointplot(x=x, y=y, kind='hex')
plt.show()
Run Code Online (Sandbox Code Playgroud)
最初的问题是......如何将散点值转换为网格值,对吧?
histogram2d确实会计算每个单元格的频率,但是,如果每个单元格除了频率之外还有其他数据,则需要做一些额外的工作。
x = data_x # between -10 and 4, log-gamma of an svc
y = data_y # between -4 and 11, log-C of an svc
z = data_z #between 0 and 0.78, f1-values from a difficult dataset
Run Code Online (Sandbox Code Playgroud)
因此,我有一个包含 X 和 Y 坐标的 Z 结果的数据集。然而,我计算的是感兴趣区域之外的几个点(大间隙),以及小感兴趣区域中的大量点。
是的,这里变得更困难,但也更有趣。一些图书馆(抱歉):
from matplotlib import pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.interpolate import griddata
Run Code Online (Sandbox Code Playgroud)
pyplot 是我今天的图形引擎,cm 是一系列颜色图,有一些有趣的选择。numpy 用于计算,griddata 用于将值附加到固定网格。
最后一项非常重要,尤其是因为 xy 点的频率在我的数据中分布不均匀。首先,让我们从一些适合我的数据的边界和任意网格大小开始。原始数据的数据点也在 x 和 y 边界之外。
#determine grid boundaries
gridsize = 500
x_min = -8
x_max = 2.5
y_min = -2
y_max = 7
Run Code Online (Sandbox Code Playgroud)
因此,我们定义了一个在 x 和 y 的最小值和最大值之间有 500 个像素的网格。
在我的数据中,高兴趣区域中的可用值远多于 500 个;而在低息区域,整个网格中的值甚至不到 200 个;x_min和之间的图形边界x_max就更少了。
因此,为了获得一张漂亮的图片,任务是获得高兴趣值的平均值并填补其他地方的空白。
我现在定义我的网格。对于每一对 xx-yy,我想要一种颜色。
xx = np.linspace(x_min, x_max, gridsize) # array of x values
yy = np.linspace(y_min, y_max, gridsize) # array of y values
grid = np.array(np.meshgrid(xx, yy.T))
grid = grid.reshape(2, grid.shape[1]*grid.shape[2]).T
Run Code Online (Sandbox Code Playgroud)
为什么形状奇怪?scipy.griddata想要一个 (n, D) 的形状。
Griddata 通过预定义的方法计算网格中每个点的一个值。我选择“最近” - 空网格点将用最近邻居的值填充。这看起来好像信息较少的区域具有较大的单元格(即使事实并非如此)。人们可以选择“线性”插值,那么信息较少的区域看起来就不那么清晰。品味问题,真的。
points = np.array([x, y]).T # because griddata wants it that way
z_grid2 = griddata(points, z, grid, method='nearest')
# you get a 1D vector as result. Reshape to picture format!
z_grid2 = z_grid2.reshape(xx.shape[0], yy.shape[0])
Run Code Online (Sandbox Code Playgroud)
然后跳,我们交给 matplotlib 来显示绘图
fig = plt.figure(1, figsize=(10, 10))
ax1 = fig.add_subplot(111)
ax1.imshow(z_grid2, extent=[x_min, x_max,y_min, y_max, ],
origin='lower', cmap=cm.magma)
ax1.set_title("SVC: empty spots filled by nearest neighbours")
ax1.set_xlabel('log gamma')
ax1.set_ylabel('log C')
plt.show()
Run Code Online (Sandbox Code Playgroud)
在 V 形的尖头部分周围,您会看到我在寻找最佳点的过程中进行了大量计算,而几乎其他地方不太有趣的部分的分辨率较低。
这是Jurgy 的最佳最近邻方法,但使用scipy.cKDTree实现。在我的测试中,它快了大约 100 倍。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.spatial import cKDTree
def data_coord2view_coord(p, resolution, pmin, pmax):
dp = pmax - pmin
dv = (p - pmin) / dp * resolution
return dv
n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)
resolution = 250
extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]
xv = data_coord2view_coord(xs, resolution, extent[0], extent[1])
yv = data_coord2view_coord(ys, resolution, extent[2], extent[3])
def kNN2DDens(xv, yv, resolution, neighbours, dim=2):
"""
"""
# Create the tree
tree = cKDTree(np.array([xv, yv]).T)
# Find the closest nnmax-1 neighbors (first entry is the point itself)
grid = np.mgrid[0:resolution, 0:resolution].T.reshape(resolution**2, dim)
dists = tree.query(grid, neighbours)
# Inverse of the sum of distances to each grid point.
inv_sum_dists = 1. / dists[0].sum(1)
# Reshape
im = inv_sum_dists.reshape(resolution, resolution)
return im
fig, axes = plt.subplots(2, 2, figsize=(15, 15))
for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 63]):
if neighbours == 0:
ax.plot(xs, ys, 'k.', markersize=5)
ax.set_aspect('equal')
ax.set_title("Scatter Plot")
else:
im = kNN2DDens(xv, yv, resolution, neighbours)
ax.imshow(im, origin='lower', extent=extent, cmap=cm.Blues)
ax.set_title("Smoothing over %d neighbours" % neighbours)
ax.set_xlim(extent[0], extent[1])
ax.set_ylim(extent[2], extent[3])
plt.savefig('new.png', dpi=150, bbox_inches='tight')
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
194080 次 |
| 最近记录: |