使用 matplotlib 处理循环数据 contour/contourf

Handling cyclic data with matplotlib contour/contourf

我正在尝试创建一个 contour/contourf 风向图 - 问题是 0/360 度不连续性正在对这两个函数造成严重破坏 - 试图插入间隙并用 all 中间值(见下文)。我尝试了各种 interpolation/shifting 个想法,但没有任何结果。有人知道如何解决这个问题吗?

一个最小工作代码示例:

levels=np.array([1000.,975.,950.,925.,900.,875.,850.,825.,800.,775.,750.,700.,650.,600.,
550.,500.,450.,400.,350.,300.,250.,225.,200.,175.,150.])
arr = np.load("arr.npy")

fig = plt.figure(figsize=(6,10))
ax = plt.subplot(111)
clevs = np.arange(-360.,360.,45.)
clevs1 = np.linspace(np.min(arr),np.max(arr),100.)

cs = plt.contour(lons,levels,arr,clevs,colors = 'k')
for c in cs.collections: c.set_linestyle('solid')
ax.set_xlabel("Longitude")
ax.set_ylabel("Pressure Level (hPa)")
ax.set_yscale("log")
plt.gca().invert_yaxis()
ax.set_yticks(levels[::2])
ax.set_yticklabels(levels[::2].astype(int))
cs1 = plt.contourf(lons,levels,arr,clevs1,cmap=plt.cm.hsv)
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("bottom", "4%", pad="8.5%")
cbar = plt.colorbar(cs1, orientation="horizontal", cax = cax)
cbar.set_ticks(clevs[::1])
cbar.set_label(r"Wind Heading")

plt.clabel(cs, inline = 1, fontsize = 18, fmt = '%1.f', manual = True)
plt.tight_layout()
plt.show()

数据here.

想象一下您可能如何对这样的数据集进行插值:您无法从略低于 360° 连续移动到 0°,除非您 unwrap 这些值(请参阅np.unwrap) 这样接近 0° 的值将被重新解释为相同的值 +360°。但是然后你再次增加 all 等高线,你最终会达到接近 2x360° 的等高线水平,然后是另一个边缘。

对于你的数据集的性质,它是物理的并且与风向有关,这绝对不是你想要的,因为你最终会陷入无限循环,一直为轮廓添加跳跃.那是因为轮廓并不真正适合这种数据

不,出于这个原因,有 wind barbs 和箭袋图,例如这个,基于您的数据集:

生成该图片的代码很简单:

x = np.load('arr.npy')
z = x/180*np.pi
u = np.cos(z)
v = np.sin(z)
plt.imshow(z, cmap='hot')
plt.quiver(u,v)

在我自己的研究中,我什至对箭头本身都不感兴趣,因为在我的工作中 180° 与 0° 相同,所以我只画棍子,没有倒钩,没有头。

我知道这在技术上不是您希望的答案,但轮廓不适合这个。如果你真的想要 "contours",你可以将数据集分成区域(例如 0 <= angle <20 等等),然后为每个区域只绘制具有中间角度的箭头(所以每个域,几个箭头都指向例如 10° 方向),但这样你就会丢失定量数据。 另一种方法是只为上述每个域着色,并在其中添加文本标签以指示它们的值。这样,您就不会在 360-0 边界的边缘看到一系列紧密排列的等高线。

我知道的唯一解决方案是将您的数据分成两部分,分别移动、解包并在绘图时再次组合它们:

import matplotlib.pyplot as plt
import numpy as np

phase_1d      = np.arange(0,360,10)
phase_levels  = np.arange(0.,360.,30.)

phase_2d,yy   = np.meshgrid([phase_1d,phase_1d],[phase_1d,phase_1d])

phase_2d_uw   = np.unwrap(np.deg2rad(phase_2d)-np.pi)
phase_2d_uw_1 = np.rad2deg(phase_2d_uw+np.pi)
phase_2d_uw_2 = np.rad2deg(phase_2d_uw-np.pi)
#
#-----------------------------------------------------------
#
plt.subplot(1,3,1)
plt.imshow(phase_2d,vmin=0,vmax=360)

plt.subplot(1,3,2)
plt.imshow(phase_2d_uw_1,vmin=0,vmax=360)

plt.subplot(1,3,3)
plt.imshow(phase_2d_uw_2,vmin=0,vmax=360)

plt.show()
#
#-----------------------------------------------------------
#
plt.subplot(1,2,1)
cl1=plt.contour(phase_2d,levels=phase_levels,colors='black',linestyles='dashed')
plt.clabel(cl1,fmt='%.0f',inline='True')

plt.subplot(1,2,2)
cl2=plt.contour(phase_2d_uw_1,levels=phase_levels,colors='black',linestyles='dashed')
plt.clabel(cl2,fmt='%.0f',inline='True')

plt.subplot(1,2,2)
cl2=plt.contour(phase_2d_uw_2,levels=phase_levels,colors='black',linestyles='dashed')
plt.clabel(cl2,fmt='%.0f',inline='True')
plt.show()        

我知道现在回答太晚了,但我一直在为这个问题苦苦挣扎,所以没有回答。

只需取角度的 sin()、cos() 值并计算该值的颜色