numpy 如何将cartopyMap的一部分标记为NaN?

avwztpqn  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(130)

我已经附上了我与x1c 0d1x工作的Map。我希望将蓝色线右侧的大部分中的值(在我提供的第二个图像中标记为

)从int更改为NaN。有没有一种方法可以选择一个特定的纬度/经度坐标和NaN周围的所有值?或者有没有其他更有效的方法?一位同事推荐了一个灵活的屏障来阻挡Map的这一部分,但我不确定如何进行编码。
我的Map是如何制作的:

fig = plt.figure(figsize=(10,10)) ax = fig.add_subplot(111,projection=rot) plot_cartopy(ax,lon,lat) plt.title("Month = May")

# set up the cartopy map

plt.contourf(lon,
            lat,
            new[4,:,:], 
            transform=ccrs.PlateCarree(), # tell matplotlib this is a map 
            cmap=cmocean.cm.thermal, # colormap 
            zorder=4 # zorder needs to be set so that it knows to plot it on top of the cartopy map  ) plt.clim(0,100) plt.colorbar()

其中“new”是一个三维数组,维度为[month,x-coordinates,y-coordinates]。
谢谢你,谢谢!

qlfbtfca

qlfbtfca1#

下面的代码给出了一些如何使用numpy.where函数将值更改为NaN的示例。
由于我没有你的数据,也不知道你的Map范围或线函数,我随机生成我的数据和线。我还生成了一个范围,可以更好地再现Map范围,但代码应该对您拥有的任何Map范围都有效。为了让您更好地理解,这里提供了全局Map和子集范围的打印示例。
在最后一个示例中,我将自定义行右侧的值更改为NaN。

import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
import cartopy
import cartopy.crs as ccrs
from cartopy.util import add_cyclic_point

# Create array
lat = np.linspace(-90,90,80)
lon = np.linspace(-180,180,120)
new = np.random.normal(size=[12,len(lat),len(lon)])

# Set map extent because my example data is global
# you wouldn't need to do this cause your data has already the proper extent
extent=[-20, 15, 5, 25] # (20°W to 15°E, 5°N to 25°N)

# Example global plot and extent (for new[4,...] as in your case)
def plot(data,title=""):
    fig = plt.figure()
    axes = [fig.add_subplot(2,1,i+1,projection=ccrs.PlateCarree()) for i in range(2)]
    # Get cyclic lon data
    plottedData,cyclicLon = add_cyclic_point(data, coord=lon, axis=-1)
    # Set extent and create rectangle box
    rect = patches.Rectangle((extent[0], extent[2]), extent[1]-extent[0], extent[3]-extent[2], 
        linewidth=1, edgecolor='r', facecolor='none', linestyle="--",zorder=3)
    for i,ax in enumerate(axes):
        ax.add_feature(cartopy.feature.COASTLINE)
        ax.add_feature(cartopy.feature.LAND, facecolor=[0.7,0.7,0.7,1])
        ax.add_feature(cartopy.feature.OCEAN, facecolor='white',zorder=2)
        im=ax.contourf(cyclicLon,lat,plottedData[4,...], cmap=plt.cm.Spectral, levels=20)
        gl=ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, alpha=0.5, linestyle='--')
        gl.right_labels = False
        gl.top_labels = False
        plt.colorbar(im)
    # Set extent to first ax and add rectangle box to second ax
    axes[0].add_patch(rect)
    axes[1].set_extent(extent)
    fig.suptitle(title)
    return axes

# Set spatial conditions on an array with ndim(t,lat,lon)
def latCondition(cond):
    return np.broadcast_to(cond,new.transpose(0,2,1).shape).transpose(0,2,1)
def lonCondition(cond):
    return np.broadcast_to(cond,new.shape)
def spatialCondition(latCond=True,lonCond=True):
    return np.logical_and(latCondition(latCond),lonCondition(lonCond))

# Base map
plot(new,title="Base Map")

####
# CHANGE SOME VALUES TO NaN USING numpy.where
####

# EX.1 Change values based on specific value
# Change points whose value > specificValue
specificValue=1
changed=np.where(new>specificValue,np.nan,new)
plot(changed,title=f"Values > {specificValue} changed to NaN")

# EX.2 Change values based on longitude:
# Change values whose longitude > longValue
longValue = -8
condition = spatialCondition(lonCond=lon > longValue)
changed=np.where(condition,np.nan,new)
plot(changed,title=f"Values with lon > {longValue} changed to NaN")

# EX.2 Change values based on longitude and latitude:
# Change values whose longitude is between longValue1 and longValue2 AND latitude < latValue
longValue1 = -115
longValue2 = 10
latValue = 12
condition = spatialCondition(latCond=lat<latValue,
    lonCond=np.logical_and(lon>longValue1, lon<longValue2))
changed=np.where(condition,np.nan,new)
plot(changed,title=f"Values with {longValue1} < lon < {longValue2} and\n lat < {latValue} changed to NaN")

# Change values based on custom line

# Generate custom line

# In my case to avoid having to interpolate the line over the map's grid,
# I generate the line over the same grid. 
# Also, to have something similar to what you have, 
# I generate my line as a vertical line, with each longitude value
# randomly chosen within the longitude extent that we selected.

lonExtent = lon[np.logical_and(lon >= extent[0],lon <= extent[1])]
lineLon = np.random.choice(lonExtent,size=len(lat))
line = [lineLon,lat]

# Get representation of custom line over the map
haxes=plot(new,title="Custom Line")
for hax in haxes:
    hax.plot(*line,
        color='blue', linewidth=2,
        transform=ccrs.PlateCarree())

# Change values to the RIGHT of the line to NaN
# So the condition is --> data's longitude >= lineLon[i] for i in range(lat)
condition = np.vstack([lon >= l for l in lineLon]) #2D Condition
changed=np.where(condition,np.nan,new)
haxes=plot(changed,title="Values to the RIGHT of the line changed to NaN")
for hax in haxes:
    hax.plot(*line,
        color='blue', linewidth=2,
        transform=ccrs.PlateCarree())
# Scatterplot to show NaN values
haxes[1].scatter(lon[np.where(np.isnan(changed[4,...]))[1]],lat[np.where(np.isnan(changed[4,...]))[0]],color='black',s=3,zorder=4)

结果可能看起来不精确的原因(例如NaN值与绘图中的自定义线不一致)是因为matplotlib contourf插值。由于matplotlib不会在任何值为NaN的情况下进行插值,因此任何接近NaN的点都将导致该空间无法进行可视化插值。在最后一个图中,我添加了一个NaN点的散点图,以向您显示它们正是自定义线右侧的点。
如果有帮助的话告诉我。

相关问题