在热图上绘制空间数据
Plotting spatial data on a heatmap
我有一个尚未解决的具有挑战性的问题。所以,我有一堆来自流体流动模拟的数据。我有两个文件:空间 (x,y,z) 数据,看起来像这样(注意,我只关心 2D,所以只关心 x 和 y 值):
(-2 -1.5 0.1)
(5 -1.5 0.1)
(-2 -1.5 0.6)
(5 -1.5 0.6)
(-2 1.92708 0.1)
...
及其对应的 velocity_magnitude 值。其中每一行对应于空间数据文件中位置的 velocty_x。例如,值 0.08 位于 (-2 -1.5 0.1).
0.08
0.07
0.1
0.34 ...
...
我想把它做成热图。我天真地首先只关注速度数据,重新格式化为二维数组,并显示了热图,但位置都是错误的。问题是空间数据没有顺序,所以按照我的方式做是行不通的。如何将 x,y 位置与实际速度值结合起来为我的数据创建热图?
如果您有兴趣在热图 Matplotlib 上渲染平均速度,Numpy 和 Scipy 是您感兴趣的软件包。让我们研究一下您的一些选择...
数据可视化
试用数据集
首先我们创建一个试验数据集:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
# Create trial dataset:
N = 10000
a = np.array([-10, -10, 0])
b = np.array([15, 15, 0])
x0 = 3*np.random.randn(N, 3) + a
x1 = 5*np.random.randn(N, 3) + b
x = np.vstack([x0, x1])
v0 = np.exp(-0.01*np.linalg.norm(x0-a, axis=1)**2)
v1 = np.exp(-0.01*np.linalg.norm(x1-b, axis=1)**2)
v = np.hstack([v0, v1])
# Render dataset:
axe = plt.axes(projection='3d')
axe.plot_trisurf(x[:,0], x[:,1], v, cmap='jet', alpha=0.5)
axe.set_xlabel("x")
axe.set_ylabel("y")
axe.set_zlabel("Speed")
axe.view_init(elev=25, azim=-45)
看起来像:
二维六边形直方图
最简单的方法可能是使用 Matplotlib hexbin 函数:
# Render hexagonal histogram:
pc = plt.hexbin(x[:,0], x[:,1], C=v, gridsize=20)
pc.axes.set_title("Heatmap")
pc.axes.set_xlabel("x")
pc.axes.set_ylabel("y")
pc.axes.set_aspect("equal")
cb = plt.colorbar(ax=pc.axes)
cb.set_label("Speed")
它呈现:
二维矩形直方图
你也可以使用numpy.histogram2D
and Matplolib imshow
:
# Bin Counts:
c, *_ = np.histogram2d(x[:,0], x[:,1], bins=20)
# Bin Weight Sums:
s, xbin, ybin = np.histogram2d(x[:,0], x[:,1], bins=20, weights=v)
lims = [xbin.min(), xbin.max(), ybin.min(), ybin.max()]
# Render rectangular histogram:
iax = plt.imshow((s/c).T, extent=lims, origin='lower')
iax.axes.set_title("Heatmap")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
cb = plt.colorbar(ax=iax.axes)
cb.set_label("Speed")
它输出:
线性插值
正如 @rioV8
所指出的,您的数据集似乎在空间上是不规则的。如果需要映射到矩形网格,可以使用mutlidimensional linear interpolator of Scipy.
from scipy import interpolate
# Create interpolator:
ndpol = interpolate.LinearNDInterpolator(x[:,:2], v)
# Create meshgrid:
xl = np.linspace(-20, 30, 20)
X, Y = np.meshgrid(xl, xl)
lims = [xl.min(), xl.max(), xl.min(), xl.max()]
# Interpolate over meshgrid:
V = ndpol(list(zip(X.ravel(),Y.ravel()))).reshape(X.shape)
# Render interpolated speeds:
iax = plt.imshow(V, extent=lims, origin='lower')
iax.axes.set_title("Heatmap")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
cb = plt.colorbar(ax=iax.axes)
cb.set_label("Speed")
它呈现:
注意:在这个版本中,刻度仍然需要以每个像素为中心。
轮廓
有了矩形网格后,您还可以绘制 Matplotlib contours:
# Render contours:
iax = plt.contour(X, Y, V)
iax.axes.set_title("Contours")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
iax.axes.grid()
iax.axes.clabel(iax)
数据操作
根据您提供的文件格式,可以使用 pandas:
轻松导入
import io
import pandas as pd
with open("spatial.txt") as fh:
file1 = io.StringIO(fh.read().replace("(", "").replace(")", ""))
x = pd.read_csv(file1, sep=" ", header=None).values
v = pd.read_csv("speed.txt", header=None).squeeze().values
我有一个尚未解决的具有挑战性的问题。所以,我有一堆来自流体流动模拟的数据。我有两个文件:空间 (x,y,z) 数据,看起来像这样(注意,我只关心 2D,所以只关心 x 和 y 值):
(-2 -1.5 0.1)
(5 -1.5 0.1)
(-2 -1.5 0.6)
(5 -1.5 0.6)
(-2 1.92708 0.1)
...
及其对应的 velocity_magnitude 值。其中每一行对应于空间数据文件中位置的 velocty_x。例如,值 0.08 位于 (-2 -1.5 0.1).
0.08
0.07
0.1
0.34 ...
...
我想把它做成热图。我天真地首先只关注速度数据,重新格式化为二维数组,并显示了热图,但位置都是错误的。问题是空间数据没有顺序,所以按照我的方式做是行不通的。如何将 x,y 位置与实际速度值结合起来为我的数据创建热图?
如果您有兴趣在热图 Matplotlib 上渲染平均速度,Numpy 和 Scipy 是您感兴趣的软件包。让我们研究一下您的一些选择...
数据可视化
试用数据集
首先我们创建一个试验数据集:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
# Create trial dataset:
N = 10000
a = np.array([-10, -10, 0])
b = np.array([15, 15, 0])
x0 = 3*np.random.randn(N, 3) + a
x1 = 5*np.random.randn(N, 3) + b
x = np.vstack([x0, x1])
v0 = np.exp(-0.01*np.linalg.norm(x0-a, axis=1)**2)
v1 = np.exp(-0.01*np.linalg.norm(x1-b, axis=1)**2)
v = np.hstack([v0, v1])
# Render dataset:
axe = plt.axes(projection='3d')
axe.plot_trisurf(x[:,0], x[:,1], v, cmap='jet', alpha=0.5)
axe.set_xlabel("x")
axe.set_ylabel("y")
axe.set_zlabel("Speed")
axe.view_init(elev=25, azim=-45)
看起来像:
二维六边形直方图
最简单的方法可能是使用 Matplotlib hexbin 函数:
# Render hexagonal histogram:
pc = plt.hexbin(x[:,0], x[:,1], C=v, gridsize=20)
pc.axes.set_title("Heatmap")
pc.axes.set_xlabel("x")
pc.axes.set_ylabel("y")
pc.axes.set_aspect("equal")
cb = plt.colorbar(ax=pc.axes)
cb.set_label("Speed")
它呈现:
二维矩形直方图
你也可以使用numpy.histogram2D
and Matplolib imshow
:
# Bin Counts:
c, *_ = np.histogram2d(x[:,0], x[:,1], bins=20)
# Bin Weight Sums:
s, xbin, ybin = np.histogram2d(x[:,0], x[:,1], bins=20, weights=v)
lims = [xbin.min(), xbin.max(), ybin.min(), ybin.max()]
# Render rectangular histogram:
iax = plt.imshow((s/c).T, extent=lims, origin='lower')
iax.axes.set_title("Heatmap")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
cb = plt.colorbar(ax=iax.axes)
cb.set_label("Speed")
它输出:
线性插值
正如 @rioV8
所指出的,您的数据集似乎在空间上是不规则的。如果需要映射到矩形网格,可以使用mutlidimensional linear interpolator of Scipy.
from scipy import interpolate
# Create interpolator:
ndpol = interpolate.LinearNDInterpolator(x[:,:2], v)
# Create meshgrid:
xl = np.linspace(-20, 30, 20)
X, Y = np.meshgrid(xl, xl)
lims = [xl.min(), xl.max(), xl.min(), xl.max()]
# Interpolate over meshgrid:
V = ndpol(list(zip(X.ravel(),Y.ravel()))).reshape(X.shape)
# Render interpolated speeds:
iax = plt.imshow(V, extent=lims, origin='lower')
iax.axes.set_title("Heatmap")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
cb = plt.colorbar(ax=iax.axes)
cb.set_label("Speed")
它呈现:
注意:在这个版本中,刻度仍然需要以每个像素为中心。
轮廓
有了矩形网格后,您还可以绘制 Matplotlib contours:
# Render contours:
iax = plt.contour(X, Y, V)
iax.axes.set_title("Contours")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
iax.axes.grid()
iax.axes.clabel(iax)
数据操作
根据您提供的文件格式,可以使用 pandas:
轻松导入import io
import pandas as pd
with open("spatial.txt") as fh:
file1 = io.StringIO(fh.read().replace("(", "").replace(")", ""))
x = pd.read_csv(file1, sep=" ", header=None).values
v = pd.read_csv("speed.txt", header=None).squeeze().values