使用Matplotlib绘制坐标致底图变形的原因及解决方法问询
地图标记点绘制时底图变形的根源与解决方法
我来帮你拆解这个问题——你遇到的地图变形,核心原因是坐标系的选择和使用不规范,具体来说:
变形的根源
地理坐标系直接绘图的固有缺陷
你给底图多边形设置的epsg:4326是地理坐标系(经纬度坐标系),它是基于地球球面的坐标系统。但Matplotlib绘制地图时,会把经纬度当作平面直角坐标来渲染——这就会在高纬度区域(比如你数据里的60°N附近)产生严重的横向拉伸:因为经度的实际地表距离在高纬度会比赤道短很多,但平面绘图时每个经度间隔的像素宽度是一致的,直接导致地图形状扭曲。商铺GeoDataFrame缺少CRS定义
你创建商铺的GeoDataFrame时,没有指定crs='epsg:4326',虽然点是从经纬度生成的,但GeoPandas不知道它的坐标系统,后续转换投影时会出错,不过这不是变形的直接原因,但也是需要修正的规范问题。
如何避免变形:转换为投影坐标系
要解决这个问题,关键是把地理坐标系转换为投影坐标系——这类坐标系是专门为平面绘图设计的,能保持区域内的空间比例、距离和形状正确。对于小范围区域,UTM(通用横轴墨卡托)投影是最优选择。
步骤1:修正商铺GeoDataFrame的CRS设置
创建shops时,一定要明确指定坐标系统:
shops = gpd.GeoDataFrame(coordinates, geometry=gpd.points_from_xy(df.longitude, df.latitude), crs='epsg:4326')
步骤2:统一转换为合适的投影坐标系
你的数据位于60°N、24-25°E,对应UTM 35N分区,EPSG代码是32635。把底图和商铺数据都转换到这个投影:
# 转换投影 polygon_proj = polygon.to_crs(epsg=32635) shops_proj = shops.to_crs(epsg=32635)
如果你不确定自己的区域对应哪个UTM分区,可以用GeoPandas的自动估算方法:
utm_crs = polygon.estimate_utm_crs() polygon_proj = polygon.to_crs(utm_crs) shops_proj = shops.to_crs(utm_crs)
步骤3:用投影后的数据绘图
最后用转换后的GeoDataFrame绘图,就能得到无变形的地图了。
完整修正后的代码
import pandas as pd import geopandas as gpd import matplotlib.pyplot as plt from shapely.geometry import Polygon # 创建简化多边形(地理坐标系) latitude = [60.41125, 59.99236, 59.99236] longitude = [24.66917, 24.66917, 25.36972] geometry = Polygon(zip(longitude, latitude)) polygon = gpd.GeoDataFrame(index=[0], crs='epsg:4326', geometry=[geometry]) # 商铺坐标数据 coordinates = {"latitude": ["60.193141", "60.292777", "60.175053", "60.163187", "60.245272", "60.154392", "60.182906"], "longitude": ["24.934214", "24.969730", "24.831068", "24.739044", "24.860983", "24.884773", "24.959175"]} df = pd.DataFrame(coordinates) # 创建商铺GeoDataFrame并指定地理坐标系 shops = gpd.GeoDataFrame(coordinates, geometry=gpd.points_from_xy(df.longitude, df.latitude), crs='epsg:4326') # 自动估算并转换为合适的UTM投影 utm_crs = polygon.estimate_utm_crs() polygon_proj = polygon.to_crs(utm_crs) shops_proj = shops.to_crs(utm_crs) # 绘制无变形的地图 ax = polygon_proj.plot(color="#3791CB") shops_proj.plot(ax=ax, color="red", markersize=20, zorder=2) plt.grid(linestyle=":", color='grey') plt.show()
内容的提问来源于stack exchange,提问作者user14074311




