matplotlib Cartopy:为什么我的圆不沿着大圆路径移动?

jjhzyzn0  于 2022-11-15  发布在  其他
关注(0)|答案(2)|浏览(176)

我在使用Cartopy时遇到问题...
我有一些位置(主要在lat中变化),我想沿着这个大圆路径画一些圆。

import cartopy.crs as ccrs
import cartopy.feature as cfeature
import cartopy
import numpy as np

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

points = np.array([[-145.624, 14.8853],
[-145.636, 10.6289],
[-145.647, 6.3713]])

proj2      = ccrs.Orthographic(central_longitude= points[1,0], central_latitude=  points[1,1]) # Spherical map
pad_radius = compute_radius(proj2, points[1,0],points[1,1], 35)

resolution = '50m'

fig = plt.figure(figsize=(112,6), dpi=96)
ax = fig.add_subplot(1, 1, 1, projection=proj2)
ax.set_xlim([-pad_radius, pad_radius])
ax.set_ylim([-pad_radius, pad_radius])

ax.imshow(np.tile(np.array([[cfeature.COLORS['water'] * 255]], dtype=np.uint8), [2, 2, 1]), origin='upper', transform=ccrs.PlateCarree(), extent=[-180, 180, -180, 180])

ax.add_feature(cfeature.NaturalEarthFeature('physical', 'land', resolution, edgecolor='black', facecolor=cfeature.COLORS['land']))
ax.add_feature(cfeature.NaturalEarthFeature('cultural', 'admin_0_countries', resolution, edgecolor='black', facecolor='none'))

# Loop over the points
# Compute the projected circle at that point
# Plot it!
for i in range(len(points)):
    thePt = points[i,0], points[i,1]
    r_or = compute_radius(proj2, points[i,0], points[i,1],  10)
    print(thePt, r_or)
    c= mpatches.Circle(xy=thePt, radius=r_or, color='red', alpha=0.3, transform=proj2, zorder=30)
    # print(c.contains_point(points[i,0], points[i,1]))
    ax.add_patch(c)
fig.tight_layout()
plt.show()

计算半径为:

def compute_radius(ortho, lon, lat, radius_degrees):
    '''
    Compute a earth central angle around lat, lon
    Return phi in terms of projection desired
    This only seems to work for non-PlateCaree projections
    '''
    phi1 = lat + radius_degrees if lat <= 0 else lat - radius_degrees
    _, y1 = ortho.transform_point(lon, phi1, ccrs.PlateCarree()) # From lon/lat in PlateCaree to ortho
    return abs(y1)

输出结果是:
145.624,14.8853),145.6366644643(-145.636,10.6289),145.644766600221(-145.647,6.371999993),145.628666684
你可以看到内插点在纬度上向下(lon几乎是恒定的),但是半径随着纬度的增加而变小,位置根本没有改变???

qcbq4gxm

qcbq4gxm1#

谢谢你重写了这个例子,这样就把事情弄清楚了!
我认为关键点是,您需要转换用于Circle的x/y坐标,反之亦然,也将半径保持为lat/lon(可能很接近但不完全相同)。现在你混合和匹配,其中半径基于正射投影,但x/y是纬度/经度。正因为如此,点确实沿着你想要的路径移动,但由于单位不正确,它离情节的原点非常近。
下面的内容可能会对您有所帮助:

points = np.array([
    [-145.624, 14.8853],
    [-145.636, 10.6289],
    [-145.647, 6.3713]],
)

proj2      = ccrs.Orthographic(
    central_longitude= points[1,0], 
    central_latitude=  points[1,1],
)
pad_radius = compute_radius(proj2, points[1,0],points[1,1], 35)

resolution = '50m'

fig, ax = plt.subplots(
    figsize=(12,6), dpi=96, subplot_kw=dict(projection=map_proj, facecolor=cfeature.COLORS['water']),
)

ax.add_feature(cfeature.NaturalEarthFeature('physical', 'land', resolution, edgecolor='black', facecolor=cfeature.COLORS['land']))
ax.add_feature(cfeature.NaturalEarthFeature('cultural', 'admin_0_countries', resolution, edgecolor='black', facecolor='none'))

ax.set_extent((-pad_radius, pad_radius, -pad_radius, pad_radius), crs=proj2)

for lon, lat in points:
    r_or = compute_radius(proj2, lon, lat,  10)

    ### I think this is what you intended!
    mapx, mapy = proj2.transform_point(lon, lat, ccrs.PlateCarree())
    ###

    c= mpatches.Circle(xy=(mapx, mapy), radius=r_or, color='red', alpha=0.3, transform=proj2, zorder=30)
    ax.add_patch(c)

7xllpg7q

7xllpg7q2#

下面是完整的答案。我没有将纬度/经度转换为正投影坐标......显然它希望圆的大小以米为单位--因此我使用一个函数将度(我知道我的圆)转换为米:

def deg2m(val_degree):
    """
    Compute surface distance in meters for a given angular value in degrees
    Uses the definition of a degree on the equator... 
    """
    geod84 = Geod(ellps='WGS84')
    lat0, lon0 = 0, 90
    _, _, dist_m = geod84.inv(lon0, lat0,  lon0+val_degree, lat0)
    return dist_m

# Data points where I wish to draw circles
points = np.array([[-111.624, 30.0],
[-111.636, 35.0],
[-111.647, 40.0]])

proj2      = ccrs.Orthographic(central_longitude= points[1,0], central_latitude=  points[1,1]) # Spherical map
pad_radius = compute_radius(proj2, points[1,0],points[1,1], 45) # Generate a region bigger than our circles

resolution = '50m'

fig = plt.figure(figsize=(112,6), dpi=96)
ax = fig.add_subplot(1, 1, 1, projection=proj2)
# Bound our plot/map
ax.set_xlim([-pad_radius, pad_radius])
ax.set_ylim([-pad_radius, pad_radius])

ax.imshow(np.tile(np.array([[cfeature.COLORS['water'] * 255]], dtype=np.uint8), [2, 2, 1]), origin='upper', transform=ccrs.PlateCarree(), extent=[-180, 180, -180, 180])
ax.add_feature(cfeature.NaturalEarthFeature('physical', 'land', resolution, edgecolor='black', facecolor=cfeature.COLORS['land']))
ax.add_feature(cfeature.NaturalEarthFeature('cultural', 'admin_0_countries', resolution, edgecolor='black', facecolor='none'))

r_or = deg2m(17) # Compute the size of circle with a radius of 17 deg

# Loop over the points
# Compute the projected circle at that point
# Plot it!
for i in range(len(points)):
    thePt = points[i,0], points[i,1]
    # Goes from lat/lon to coordinates in our Orthographic projection
    mapx, mapy = proj2.transform_point(points[i,0], points[i,1], ccrs.PlateCarree())
    c= mpatches.Circle(xy=(mapx, mapy), radius=r_or, color='red', alpha=0.3, transform=proj2, zorder=30)
    ax.add_patch(c)
fig.tight_layout()
plt.show()

我已经验证了deg 2 m程序的工作,因为它是大约17度的纬度从Phoenix城AZ到加拿大边境(约),这是附近的这些测试点。

相关问题