提问人:LordHammer 提问时间:3/17/2023 最后编辑:LordHammer 更新时间:3/28/2023 访问量:78
如何使用地理/坐标而不是像素坐标沿曲线提取一维轮廓?
How to extract a One dimensional profile along a curve using Geographic/Co-ordinates instead of pixel Coords?
问:
如何从给定地理坐标而不是像素坐标的 Array 中获取 1D 轮廓。
我在地理坐标(NASA GOLD Mission)中有辐射度数据。
每个半球的数据都存储在单独的文件中。我想沿一条曲线(北纬 10 度)拍摄拼接半球的 1D 剖面图,该曲线以 Geo 坐标表示,
我试图使用map_coordinates来调整这里的答案,但我意识到它是在像素坐标中,这就是为什么我认为配置文件与地图不对应的原因;
为了获得一维剖面图,我将地图坐标的输出与输入曲线 (X) 值作图,以便获得经度的变化。
另一个黄色的剖面图也与地图中的数据不对应;
当我使用 imshow 绘制数据时,它看起来与地图上不同;
数据和 Python 代码在这里 数据+代码;
from netCDF4 import Dataset
import glob, matplotlib,os;matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy.ma as ma
Mag = pd.read_csv(r"\mag_cords.csv")
X_dip10s,Y_dip10s = Mag.LON10S.to_numpy(),Mag.LAT10S.to_numpy()
g = Dataset('GOLD_L1C_CH*23*.nc','r');
wavelength = g.variables['WAVELENGTH'][:]
radiance = g.variables['RADIANCE'][:]
lat = g.variables['REFERENCE_POINT_LAT'][:]
lon = g.variables['REFERENCE_POINT_LON'][:]
g.close()
O5s_ids = np.argwhere((134.3 <= wavelength[50,25,:]) & (wavelength[50,25,:] <= 137.7))
O5s = np.array(np.nansum(radiance[:,:,O5s_ids],axis = 2))*.04 # integrate under the peak!
O5s = np.transpose(O5s[:,:,0])
x=lon[9:-8,9:-8];y=lat[9:-8,9:-8];z=O5s[9:-8,9:-8].T;z=abs(z)#To remove Nans
z2=np.ma.masked_array(z, (z > 30))
Zs=scipy.ndimage.map_coordinates(np.transpose(z),
np.vstack((X_dip10s,Y_dip10s)),
mode="nearest")
Xs=scipy.ndimage.map_coordinates(np.transpose(x),
np.vstack((X_dip10s,Y_dip10s)),mode="nearest")
fig=plt.figure(figsize=(10,10))
axarr = fig.add_subplot(211,projection=ccrs.PlateCarree())
ax2 = fig.add_subplot(212)
grid_lines =axarr.gridlines(draw_labels=True'); axarr.coastlines()
cs1 = axarr.contourf(x,y, z2, transform=ccrs.PlateCarree(),cmap='jet',levels=50)
ax2.plot(X_dip10s,Zs, 'k-', Xs ,Zs, 'k-')
[1]: https://i.stack.imgur.com/66C4P.png
答:
1赞
raphael
3/20/2023
#1
有趣的问题!
我是 EOmaps 的开发人员,EOmaps 是一个旨在简化创建这种自定义地理数据分析小部件的库,所以我很感兴趣:-)
我快速浏览了一下您的数据...这是一个非常奇怪的 netcdf,我不知道是什么定义了您用来识别点的行,所以我只是重用您的代码来提取数据。
这是一个快速解决方案,它使用 KDTree 来识别相对于线点的最近点......它不是 100% 精确,因为它根据以度为单位定义的最大距离而不是地球上的实际距离来识别这些点,但它工作得很好,我认为如果你需要更精确的东西,你应该能够从这里拿走它......
同样重要的是要注意,此方法将向您显示实际数据,而不是由用于显示数据的算法创建的一些插值点!(所以这条线不会很好看,它只会显示最接近这条线的实际数据值)
from pathlib import Path
from itertools import chain
from scipy.spatial import KDTree
import xarray as xar
import pandas as pd
import numpy as np
from eomaps import Maps
# --------------------------------------------- read the data
p = Path(r"GOLD_data-20230319T161539Z-001\GOLD_data")
with xar.open_dataset(p / "GOLD_L1C_CHA_NI1_2018_286_23_10_v04_r01_c01.nc") as ncfile:
lon, lat = ncfile.REFERENCE_POINT_LON.values, ncfile.REFERENCE_POINT_LAT.values
wavelength = ncfile.WAVELENGTH.values
radiance = ncfile.RADIANCE.values
O5s_ids = np.argwhere((134.3 <= wavelength[50,25,:]) & (wavelength[50,25,:] <= 137.7))
O5s = np.array(np.nansum(radiance[:,:,O5s_ids],axis = 2))*.04 # integrate under the peak!
O5s = np.transpose(O5s[:,:,0])
x=lon[9:-8,9:-8]
y=lat[9:-8,9:-8]
z=O5s[9:-8,9:-8].T
Mag = pd.read_csv(p / "mag_cords.csv")
X_dip10s,Y_dip10s = Mag.LON10S.to_numpy(),Mag.LAT10S.to_numpy()
line = np.column_stack((X_dip10s, Y_dip10s))
# --------------------------------------------- create a new map
m = Maps(ax=211, crs=4326)
m.set_extent((-61.8,-20.5,-1.5,24.5))
m.add_feature.preset.coastline()
m.add_feature.preset.ocean()
# plot the data
m.set_data(data=z, x=x, y=y, crs=4326)
m.set_shape.ellipses(radius=0.35)
m.set_classify.UserDefined(bins=np.linspace(0, 20, 11))
m.plot_map(cmap="viridis", vmin=0, vmax=28)
m.add_colorbar(orientation="vertical")
# add a normal matplotlib axis (and share x-limits)
ax = m.f.add_subplot(212)
ax.sharex(m.ax)
# turn off navigation on the normal matplotlib plot
ax.set_navigate(False)
# position axes
m.apply_layout(
{'figsize': [6.95, 4.8],
'0_map': [0.1, 0.44678, 0.5875, 0.53552],
'1_cb': [0.75, 0.04546, 0.2125, 0.95484],
'1_cb_histogram_size': 0.8,
'2_': [0.1, 0.10859, 0.5875, 0.32578]}
)
# setup a new map-layer (will be used to draw identified points)
m2 = m.new_layer()
# --------------------------------------------- identify points along line
tree = KDTree(np.column_stack((x.ravel(), y.ravel())))
def get_lineoffset(pos, **kwargs):
# get the offset required to shift the line to the click position
x, y = line.T
minxid = np.argmin(abs(pos[0] - x))
offset = pos[1] - y[minxid]
return offset
def identify_points(pts, max_dist):
# identify closest points with respect to the line
tree2 = KDTree(pts)
q = tree2.query_ball_tree(tree, max_dist)
q = list(chain(*[i for i in q if len(i) > 0]))
coords = tree.data[q].T
data = z.ravel()[q]
return coords, data
def indicate_found_points(pts, offset=0, max_dist=1):
# offset line
pts = pts + [0, offset]
# identify closest points
coords, data = identify_points(pts, max_dist=max_dist)
# plot identified points on the map (replace on each click)
m2.set_data(data, coords[0], coords[1])
m2.set_shape.ellipses(radius=0.2)
m2.plot_map(set_extent=False, zorder=2, fc="r")
# sort found points so we can plot a line
sortp = np.argsort(coords[0])
lx, ly = coords[0][sortp], data[sortp]
# plot a line on the map
l, = m.ax.plot(*pts.T, c="r", lw=0.5)
# remove it on next pick
m.cb.pick.add_temporary_artist(l)
# plot data on normal matpltoib plot
l2, = ax.plot(lx, ly, lw=0.25, c="k", zorder=0)
# color points same as in the map
sc = ax.scatter(lx, ly, c=ly, s=10, norm=m._norm, cmap=m._cbcmap)
# remove it on next pick
m.cb.pick.add_temporary_artist(l2)
m.cb.pick.add_temporary_artist(sc)
ax.relim()
ax.autoscale_view()
m.redraw()
def callback(pos, max_dist=1, **kwargs):
offset = get_lineoffset(pos)
indicate_found_points(line, offset=offset, max_dist=max_dist)
# attach the callback to the map
m.cb.pick.attach(callback, max_dist=0.75)
评论
0赞
LordHammer
3/26/2023
这看起来是一个很好的解决方案。我使用 minicondas Dbn 安装,但是当我运行此命令“from eomaps import Maps”错误时:“ ImportError:无法从'matplotlib.tri'导入名称'TriMesh'(C:\Users\simba\miniconda3\envs\eomaps\Lib\site-packages\matplotlib\tri_init_.py)”
0赞
raphael
3/27/2023
嘿,这是因为您正在使用...更新应该可以解决问题!(github.com/matplotlib/matplotlib/issues/24105)(我必须为此实现一个向后移植,以便旧版本也可以工作......matplotlib v3.5.x
matplotlib v3.6.x
0赞
LordHammer
3/27/2023
嗨 stackoverflow.com/users/9703451/raphael,我实际上在我的 miniconda 上安装了 matplotlib 3.7.1。我应该降级到 3.6.0 吗?
0赞
raphael
3/27/2023
嘿嘿,这确实出乎意料......您是否可以使用旧的 EOmaps 版本?(因为不再从...我刚刚测试过,我没有遇到任何问题......我在这里打开了一个关于 v3.5.x 的问题......如果您提供有关设置的一些详细信息,我可以尝试帮助查明您的问题。eomaps v4.4.3
TriMesh
matplotlib.tri
eomaps v6.3
matplotlib v3.7.1
0赞
LordHammer
3/28/2023
嘿,我在哪里可以得到这些详细信息?
评论