使用稀疏数据在 python 中绘制二维等高线图
Plotting a 2d contour plot in python with sparse data
我有一些来自海洋环流模型 (MITgcm) 的输出数据。这是一个理想化的通道(笛卡尔),所以幸运的是几何形状并不混乱。
我想在 y-z 平面上绘制一些场(速度、温度等)。模拟域涉及 30 个垂直层,其中每个层都是一个 800x400 y-x 网格。我将每个字段存储在形状为 (30, 800, 400) 的 numpy 数组中,分别为 z、y、x。
我可以轻松绘制 30 个垂直级别的 x-y 平面切片。我可以使用 matplotlib 的 contourf 或 imshow 并将范围更改为以公里为单位的正确物理值。
问题是垂直层间距不均匀。我有 Z 的网格数据,它告诉我每个层对应的物理深度(以米为单位)。
Z 为:[-5。 -15。 -25。 -36。 -49。 -65。 -84。 -105.5 -130.5 -159.5 -192.5 -230。 -273。 -322.5 -379。 -443。 -515。 -596。 -688。 -792。 -909.5 -1042.5 -1192.5 -1362。 -1553.5 -1770。 -2015。
-2285。 -2565。 -2845.]
我试图通过创建一个包含 2985(因为全域深度为 2985m)'vertical' 层的空矩阵来解决这个问题,并在给定的 30 层的相应位置输入 y 数据通过上面的Z(这里yz_zonal是一个(30,800)数据值矩阵):
yz_matrix = np.empty((2985, 800)) #empty matrix for yz-plane data, vertical extent is 2985 (m)
for i in range(len(Z)):
yz_matrix[round(-Z[i])] = yz_zonal[i] #set matrix values to correct depths
然后,如果我尝试使用 matplotlib 的 imshow 绘制 yz_matrix,方法是:
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlabel('y (km)')
ax.set_ylabel('z (m)')
yzplot = ax.imshow(yz_matrix, aspect='auto', interpolation='gaussian', cmap='inferno', extent=[0,2000,-2985,0])
plt.colorbar(yzplot)
我刚刚得到这个数字:BAD y-z plot of velocity data
在正确的物理 z 位置有 30 条数据值,但它们之间有一大堆零。我只想在 30 个条带之间插入数据并忽略所有其他点。
如果有人能帮我解决这个问题就太好了。提前致谢!
彼得
从 matplotlib 站点查看此 example,尤其是函数 np.meshgrid
和 plt.contourf
。像这样不规则 z
的东西会起作用:
z = [1,2,5,10]
x = [1,2,3,4,5,6,7,8]
zz, xx = np.meshgrid(z, x)
# create some data
values = np.random.randn(len(x), len(z))
plt.contourf(zz, xx, values)
plt.show()
您可以直接将 yz_matrix
绘制为 pcolormesh
,给出 z 和 y 数据的网格作为坐标。这将导致不同大小的单元格延伸到 z 中的下一个值。见下图左图。
您也可以在新的更精细的网格上插入数据。为此,可以使用 scipy.interpolate.griddata
。
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
z = np.array([-5.,-15.,-25.,-36.,-49.,-65.,-84.,-105.5,-130.5,-159.5,-192.5,
-230.,-273.,-322.5,-379.,-443.,-515.,-596.,-688.,-792.,-909.5,
-1042.5,-1192.5,-1362.,-1553.5,-1770.,-2015.,-2285.,-2565.,-2845.])
y = np.arange(0,100)
yz_matrix = np.cumsum(np.random.rand(len(z), len(y)), axis=0)
fig, (ax, ax2) = plt.subplots(ncols=2)
# plot raw data as pcolormesh
Y,Z = np.meshgrid(y,z[::-1])
ax.pcolormesh(Y,Z, yz_matrix, cmap='inferno')
ax.set_title("pcolormesh data")
# now interpolate data to new grid
zi = np.arange(-2845,-5)
YI,ZI = np.meshgrid(y,zi)
points = np.c_[Y.flatten(),Z.flatten()]
interp = griddata(points, yz_matrix.flatten(), (YI,ZI), method='linear')
ax2.pcolormesh(YI,ZI, interp, cmap='inferno')
ax2.set_title("pcolormesh interpolated")
plt.show()
我有一些来自海洋环流模型 (MITgcm) 的输出数据。这是一个理想化的通道(笛卡尔),所以幸运的是几何形状并不混乱。
我想在 y-z 平面上绘制一些场(速度、温度等)。模拟域涉及 30 个垂直层,其中每个层都是一个 800x400 y-x 网格。我将每个字段存储在形状为 (30, 800, 400) 的 numpy 数组中,分别为 z、y、x。
我可以轻松绘制 30 个垂直级别的 x-y 平面切片。我可以使用 matplotlib 的 contourf 或 imshow 并将范围更改为以公里为单位的正确物理值。
问题是垂直层间距不均匀。我有 Z 的网格数据,它告诉我每个层对应的物理深度(以米为单位)。
Z 为:[-5。 -15。 -25。 -36。 -49。 -65。 -84。 -105.5 -130.5 -159.5 -192.5 -230。 -273。 -322.5 -379。 -443。 -515。 -596。 -688。 -792。 -909.5 -1042.5 -1192.5 -1362。 -1553.5 -1770。 -2015。 -2285。 -2565。 -2845.]
我试图通过创建一个包含 2985(因为全域深度为 2985m)'vertical' 层的空矩阵来解决这个问题,并在给定的 30 层的相应位置输入 y 数据通过上面的Z(这里yz_zonal是一个(30,800)数据值矩阵):
yz_matrix = np.empty((2985, 800)) #empty matrix for yz-plane data, vertical extent is 2985 (m)
for i in range(len(Z)):
yz_matrix[round(-Z[i])] = yz_zonal[i] #set matrix values to correct depths
然后,如果我尝试使用 matplotlib 的 imshow 绘制 yz_matrix,方法是:
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlabel('y (km)')
ax.set_ylabel('z (m)')
yzplot = ax.imshow(yz_matrix, aspect='auto', interpolation='gaussian', cmap='inferno', extent=[0,2000,-2985,0])
plt.colorbar(yzplot)
我刚刚得到这个数字:BAD y-z plot of velocity data
在正确的物理 z 位置有 30 条数据值,但它们之间有一大堆零。我只想在 30 个条带之间插入数据并忽略所有其他点。
如果有人能帮我解决这个问题就太好了。提前致谢!
彼得
从 matplotlib 站点查看此 example,尤其是函数 np.meshgrid
和 plt.contourf
。像这样不规则 z
的东西会起作用:
z = [1,2,5,10]
x = [1,2,3,4,5,6,7,8]
zz, xx = np.meshgrid(z, x)
# create some data
values = np.random.randn(len(x), len(z))
plt.contourf(zz, xx, values)
plt.show()
您可以直接将 yz_matrix
绘制为 pcolormesh
,给出 z 和 y 数据的网格作为坐标。这将导致不同大小的单元格延伸到 z 中的下一个值。见下图左图。
您也可以在新的更精细的网格上插入数据。为此,可以使用 scipy.interpolate.griddata
。
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
z = np.array([-5.,-15.,-25.,-36.,-49.,-65.,-84.,-105.5,-130.5,-159.5,-192.5,
-230.,-273.,-322.5,-379.,-443.,-515.,-596.,-688.,-792.,-909.5,
-1042.5,-1192.5,-1362.,-1553.5,-1770.,-2015.,-2285.,-2565.,-2845.])
y = np.arange(0,100)
yz_matrix = np.cumsum(np.random.rand(len(z), len(y)), axis=0)
fig, (ax, ax2) = plt.subplots(ncols=2)
# plot raw data as pcolormesh
Y,Z = np.meshgrid(y,z[::-1])
ax.pcolormesh(Y,Z, yz_matrix, cmap='inferno')
ax.set_title("pcolormesh data")
# now interpolate data to new grid
zi = np.arange(-2845,-5)
YI,ZI = np.meshgrid(y,zi)
points = np.c_[Y.flatten(),Z.flatten()]
interp = griddata(points, yz_matrix.flatten(), (YI,ZI), method='linear')
ax2.pcolormesh(YI,ZI, interp, cmap='inferno')
ax2.set_title("pcolormesh interpolated")
plt.show()