使用Basemap时迭代Pandas数据框及经纬度旋转保陆地位置问题
搞定经纬度旋转变换的两个问题:遍历Pandas数据框 + 修复while循环
一、用Basemap遍历Pandas数据框检查陆地属性
要逐个验证数据框里的经纬度点是否在陆地,结合Basemap的工具和Pandas的遍历方法很容易实现,给你两种常用方案:
方案1:用df.apply()批量处理(推荐,效率更高)
这种方式贴合Pandas的向量化思维,代码干净利落:
from mpl_toolkits.basemap import Basemap import pandas as pd # 先初始化Basemap实例,这里用圆柱投影(cyl),你可以根据需求换其他投影 m = Basemap(projection='cyl', llcrnrlat=-90, urcrnrlat=90, llcrnrlon=-180, urcrnrlon=180, resolution='l') # 模拟你的数据框 df = pd.DataFrame({ '原始经度': [116.4, 120.1, 100.5], '原始纬度': [39.9, 30.2, 25.0] }) # 定义检查陆地的函数 def check_land(row): # 把经纬度转成Basemap的投影坐标(cyl投影下和原坐标一致,但养成好习惯总是对的) x, y = m(row['原始经度'], row['原始纬度']) # 用Basemap的is_land方法判断 return m.is_land(x, y) # 给数据框新增一列存检查结果 df['是否为陆地'] = df.apply(check_land, axis=1) print(df)
方案2:用iterrows()逐行遍历(适合需要自定义操作的场景)
如果需要在遍历过程中同时做旋转变换这类操作,逐行循环更灵活:
for idx, row in df.iterrows(): original_lon, original_lat = row['原始经度'], row['原始纬度'] x, y = m(original_lon, original_lat) is_land = m.is_land(x, y) # 这里可以直接加旋转变换的代码,或者更新数据框 df.at[idx, '是否为陆地'] = is_land
小贴士:数据量大的话,apply()比iterrows()快不少,优先选前者。
二、修复旋转变换的while循环问题
你说加了while循环后脚本出问题,十有八九是循环没设退出边界导致死循环,或者旋转后的坐标始终碰不到陆地。给你一个更稳的循环思路:
核心要点
- 一定要设最大迭代次数,避免无限跑
- 每次旋转后用Basemap检查是否在陆地
- 满足条件就退出,到次数还不行就返回原坐标(或者给提示)
示例代码
import numpy as np # 先写个旋转变换函数,这里用平面旋转示例,你可以换成自己的球面旋转逻辑(建议用pyproj处理球面更准确) def rotate_coords(original_lon, original_lat, angle): # 简化版:把经纬度转平面笛卡尔坐标 x = original_lon * np.cos(np.radians(original_lat)) y = original_lat # 旋转矩阵 rot_matrix = np.array([[np.cos(np.radians(angle)), -np.sin(np.radians(angle))], [np.sin(np.radians(angle)), np.cos(np.radians(angle))]]) x_rot, y_rot = rot_matrix @ np.array([x, y]) # 转回经纬度(简化版,实际球面旋转要复杂些) lon_rot = x_rot / np.cos(np.radians(y_rot)) lat_rot = y_rot return lon_rot, lat_rot # 循环旋转直到找到陆地坐标的函数 def rotate_until_land(original_lon, original_lat, max_iter=100, step_angle=5): current_lon, current_lat = original_lon, original_lat for i in range(max_iter): # 每次旋转角度递增(你也可以固定角度,或者随机角度,看需求) current_lon, current_lat = rotate_coords(original_lon, original_lat, step_angle * i) # 检查是否在陆地 x, y = m(current_lon, current_lat) if m.is_land(x, y): return current_lon, current_lat # 到次数还没找到,给提示并返回原坐标 print(f"警告:旋转{max_iter}次后仍没找到陆地坐标,返回原坐标") return original_lon, original_lat # 把这个函数应用到整个数据框 df['旋转后经度'], df['旋转后纬度'] = zip(*df.apply(lambda row: rotate_until_land(row['原始经度'], row['原始纬度']), axis=1))
常见坑排查
- 死循环:没设
max_iter的话,要是原坐标在大洋中心,旋转一万次也碰不到陆地,脚本直接卡死,一定要加这个限制 - 旋转逻辑不准:平面旋转适合小范围坐标,要是跨半球旋转,必须用球面旋转(比如用
pyproj的Transformer做坐标转换),否则结果会离谱 - 陆地判断不准:Basemap的
is_land()分辨率由初始化时的resolution参数决定('l'是低分辨率,'h'是高分辨率),需要精确判断就调高点分辨率
内容的提问来源于stack exchange,提问作者MsCurious
相关产品推荐
相关产品推荐

