# GeoSciPlot · 制图经验全文 > 本文件是 https://geosciplot.zbhgis.com/guide/ 栏目全部文章的纯文本全文,供 AI 引擎整段引用。 > 索引文件:https://geosciplot.zbhgis.com/llms.txt · 图片目录见 https://geosciplot.zbhgis.com/sitemap.xml ## 顶刊中的全球地图投影(五)-Orthographic投影Python实现 - URL: https://geosciplot.zbhgis.com/guide/map-projection-orthographic/ - 日期: 2026-03-06 - 摘要: 上一篇文章介绍了Spilhaus地图投影的补充,这篇将会进一步对Orthographic投影进行补充,帮助大家能够绘制出预期中的地图投影效果。 前言 上一篇文章介绍了Spilhaus地图投影的补充,这篇将会进一步对Orthographic投影进行补充,帮助大家能够绘制出预期中的地图投影效果。 完整代码及数据均开源,获取方式见文末。 Orthographic投影 Orthographic投影是什么 正射投影(Orthographic projection)是一种方位透视投影(azimuthal perspective projection),其投影中心位于地球无限远处,导致所有投影射线相互平行,等效于平行光源从无穷远照射地球表面至切平面(通常为与球体相切的平面)。在现代,正射投影主要用于模拟卫星或太空视角的真实视觉效果、极地/区域专题展示。 参考: https://en.wikipedia.org/wiki/Orthographic_map_projection 以下图片来源: https://doi.org/10.1038/s41561-025-01894-y 不同的Orthographic投影 实现也比较简单,就是通过内置的 中心经度,中心纬度,方位角 三个参数调节。通过以下代码即可看到不同参数下的正射投影地图,适合极地或洲际或国家尺度研究。 orthographic.py PYTHON """ ------------------------------------------------------------------------------- @Author : zbhgis @Github : https://github.com/zbhgis @Description : different views of orthographic projection ------------------------------------------------------------------------------- """ import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature # 设置投影名称与对应的投影 projections = [ ( "orthographic (0, 0, 0)" , ccrs . Orthographic ()), ( "orthographic (100, 40, 0)" , ccrs . Orthographic ( 100 , 40 , 0 )), ( "orthographic (-100, 40, 0)" , ccrs . Orthographic ( - 100 , 40 , 0 )), ( "orthographic (100, 40, 45)" , ccrs . Orthographic ( 100 , 40 , 45 )), ( "orthographic (100, 40, 90)" , ccrs . Orthographic ( 100 , 40 , 90 )), ( "orthographic (0, 90, 0)" , ccrs . Orthographic ( 0 , 90 , 0 )), ( "orthographic (0, 90, 180)" , ccrs . Orthographic ( 0 , 90 , 180 )), ] # 每个投影一张图片 for proj_name , proj in projections : fig = plt . figure ( figsize = ( 10 , 10 )) ax = fig . add_subplot ( 1 , 1 , 1 , projection = proj ) ax . add_feature ( cfeature . OCEAN , facecolor = "#1f77b4" , zorder = 0 ) ax . add_feature ( cfeature . LAND , facecolor = "none" , edgecolor = "none" , zorder = 1 ) ax . coastlines ( resolution = "50m" , color = "black" ) ax . gridlines ( draw_labels = True , linestyle = "--" ) ax . set_title ( proj_name , fontsize = 16 , pad = 10 ) print ( proj_name ) plt . savefig ( f "./fig_res/ { proj_name } .png" , dpi = 100 , bbox_inches = "tight" , ) plt . close ( fig ) 打印结果 PLAIN orthographic (0, 0, 0) orthographic (100, 40, 0) orthographic (-100, 40, 0) orthographic (100, 40, 45) orthographic (100, 40, 90) orthographic (0, 90, 0) orthographic (0, 90, 90) orthographic (0, 90, 180) 绘制结果 Orthographic() Orthographic(100, 40, 0) Orthographic(-100, 40, 0) Orthographic(100, 40, 45) Orthographic(100, 40, 90) Orthographic(0, 90, 0) Orthographic(0, 90, 180) Orthographic投影范围设置 在绘制北半球地图时,热带区域并不是研究重点,需要突出极地或温带部分,因此绘制时会截取出某个纬度以北或以南的部分。 代码中以北极地区为例,设置了20°,40°,60°的范围。核心部分就是set_extent()至set_boundary()之间的代码。通过绘制一个圆形将所需的部分裁出即可。 orthographic2.py PYTHON """ ------------------------------------------------------------------------------- @Author : zbhgis @Github : https://github.com/zbhgis @Description : different extents of orthographic projection ------------------------------------------------------------------------------- """ import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature import numpy as np import matplotlib.path as mpath import matplotlib.ticker as mticker extents = [ 60 , 40 , 20 ] # 每个投影一张图片 for extent in extents : proj_name , proj = ( "orthographic (0, 90, 0)" , ccrs . Orthographic ( 0 , 90 , 0 )) fig = plt . figure ( figsize = ( 10 , 10 )) ax = fig . add_subplot ( 1 , 1 , 1 , projection = proj ) ax . set_extent ([ - 180 , 180 , extent , 90 ], crs = ccrs . PlateCarree ()) theta = np . linspace ( 0 , 2 * np . pi , 100 ) center = ( 0.5 , 0.5 ) radius = 0.5 vertices = np . column_stack ( [ center [ 0 ] + radius * np . cos ( theta ), center [ 1 ] + radius * np . sin ( theta )] ) circle_path = mpath . Path ( vertices ) ax . set_boundary ( circle_path , transform = ax . transAxes ) ax . add_feature ( cfeature . OCEAN , facecolor = "#1f77b4" , zorder = 0 ) ax . add_feature ( cfeature . LAND , facecolor = "none" , edgecolor = "none" , zorder = 1 ) ax . coastlines ( resolution = "50m" , color = "black" ) gl = ax . gridlines ( draw_labels = True , linestyle = "--" , alpha = 0.5 , linewidth = 0.8 , ) gl . xlocator = mticker . MultipleLocator ( 20 ) gl . ylocator = mticker . MultipleLocator ( 20 ) ax . set_title ( proj_name , fontsize = 16 , pad = 10 ) print ( proj_name ) plt . savefig ( f "./fig_res/ { proj_name } _ { extent } .png" , dpi = 100 , bbox_inches = "tight" , ) plt . close ( fig ) 打印结果 PLAIN orthographic (0, 90, 0) orthographic (0, 90, 0) orthographic (0, 90, 0) 绘制结果 写在最后 写在最后 完整代码及相关数据文件会在以下github仓库中开源,若有帮助欢迎点个star,不胜感激。 https://github.com/zbhgis/Projects 或者在微信公众号后台回复关键词“ 代码获取 ”即可获取百度网盘链接,找到对应名称的文件夹即可(百度网盘链接可能隔几天才会同步)。 代码中使用了很多相对路径,建议获取的时候下载完整文件夹。 如有问题,欢迎添加个人微信交流。 --- ## 顶刊中的全球地图投影(四)-Spilhaus投影Python实现 - URL: https://geosciplot.zbhgis.com/guide/map-projection-spilhaus/ - 日期: 2026-03-05 - 摘要: 之前的文章介绍了一些地图投影的Python简单实现,这篇将会进一步对Spilhaus投影进行补充,帮助大家能够绘制出预期中的地图投影效果。 前言 之前的文章介绍了一些地图投影的Python简单实现,这篇将会进一步对Spilhaus投影进行补充,帮助大家能够绘制出预期中的地图投影效果。 完整代码及数据均开源,获取方式见文末。 Spilhaus投影 Spilhaus投影是什么 以下图片来源: https://doi.org/10.1126/sciadv.ady6314 Spilhaus投影的海陆边界 直接绘制Spilhaus投影,海陆边界并不明显,也就是难以突出海洋部分,因此可以直接使用Natural Earth提供的海陆边界数据,就陆地部分设置为白色或者透明即可(或者自行添加矢量数据也可以)。 这个代码绘制的结果相较于之前,海洋部分就明显了许多。 spilhaus.py PYTHON """ ------------------------------------------------------------------------------- @Author : zbhgis @Github : https://github.com/zbhgis @Description : spilhaus without basemap ------------------------------------------------------------------------------- """ import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature fig = plt . figure ( figsize = ( 10 , 10 ), dpi = 100 ) ax = fig . add_subplot ( 1 , 1 , 1 , projection = ccrs . Spilhaus ()) ax . set_global () ax . add_feature ( cfeature . OCEAN , facecolor = "#1f77b4" , zorder = 0 ) ax . add_feature ( cfeature . LAND , facecolor = "none" , edgecolor = "none" , zorder = 1 ) ax . coastlines ( resolution = "50m" , color = "black" ) ax . gridlines ( draw_labels = True , linestyle = "--" ) title = "spilhaus_nobasemap" plt . title ( title ) plt . savefig ( f "./fig_res/ { title } .png" , dpi = 100 , bbox_inches = "tight" , ) print ( "ok" ) 打印结果 PLAIN ok 绘制结果 Spilhaus投影的海洋底图 Spilhaus投影海洋部分是主体,一般底图是蓝色系或蓝色渐变色。除了像上面的代码直接填充蓝色,也可以使用自定义地图或者数据作为海洋底图。 代码中以dem数据为例,在上述代码的基础上进行改进,设置了一个自定义蓝色渐变色带来渲染DEM数据,作为海洋底图。添加数据的逻辑与之前的代码类似。 spilhaus2.py PYTHON """ ------------------------------------------------------------------------------- @Author : zbhgis @Github : https://github.com/zbhgis @Description : spilhaus with gradient blue basemap ------------------------------------------------------------------------------- """ import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature import rasterio import matplotlib.colors as mcolors plt . rcParams [ "font.family" ] = "Arial" dem_tif = "./data_res/gebco_dem.tif" fig = plt . figure ( figsize = ( 10 , 10 ), dpi = 100 ) ax = fig . add_subplot ( 1 , 1 , 1 , projection = ccrs . Spilhaus ()) ax . set_global () ax . add_feature ( cfeature . LAND , facecolor = "white" , edgecolor = "none" , zorder = 1 ) ax . coastlines ( resolution = "50m" , color = "black" ) ax . gridlines ( draw_labels = True , linestyle = "--" ) # 自定义色带 ocean_colors = [ "#f4fdfe" , "#c4edfa" , "#94dff6" , "#63cbee" , "#4a91cb" , "#2f56a9" , "#17208b" , "#0a017a" , "#0b007a" , "#0c075f" , ] custom_cmap = mcolors . LinearSegmentedColormap . from_list ( "custom_ocean" , ocean_colors , N = 256 ) with rasterio . open ( dem_tif ) as src : dem_data = src . read ( 1 , masked = True ) dem_data = - dem_data left , bottom , right , top = src . bounds extent = [ left , right , bottom , top ] im = ax . imshow ( dem_data , extent = extent , transform = ccrs . PlateCarree (), origin = "upper" , cmap = custom_cmap , vmin = 0 , vmax = 8000 , alpha = 0.8 , interpolation = "bilinear" , zorder = 0 , ) # 添加DEM色带 cbar = fig . colorbar ( im , ax = ax , orientation = "horizontal" , pad = 0.04 , aspect = 40 , shrink = 0.6 , extend = "max" , ) cbar . set_ticks ([ 0 , 2000 , 4000 , 6000 , 8000 ]) cbar . set_ticklabels ([ "0" , "2" , "4" , "6" , "8" ]) cbar . ax . tick_params ( labelsize = 16 , labelcolor = "black" , length = 0 , ) cbar . set_label ( "Depth (km)" , fontsize = 18 ) # 添加标题并保存 title = "spilhaus_dem" plt . title ( title , fontsize = 20 ) plt . savefig ( f "./fig_res/ { title } .png" , dpi = 100 , bbox_inches = "tight" , ) print ( "ok" ) 打印结果 PLAIN ok 绘制结果 写在最后 完整代码及相关数据文件会在以下github仓库中开源,若有帮助欢迎点个star,不胜感激。 https://github.com/zbhgis/Projects 或者在微信公众号后台回复关键词“ 代码获取 ”即可获取百度网盘链接,找到对应名称的文件夹即可(百度网盘链接可能隔几天才会同步)。 代码中使用了很多相对路径,建议获取的时候下载完整文件夹。 该系列下一篇会再对Orthographic投影绘制进行补充。 如有问题,欢迎添加个人微信交流。 --- ## 顶刊中的全球地图投影(三)-Python简单实现 - URL: https://geosciplot.zbhgis.com/guide/map-projection-python/ - 日期: 2026-03-04 - 摘要: 之前的文章介绍了一些地图投影以及如何基本的用途。这篇文章介绍怎么在代码中实现,并添加一些矢量与栅格数据进行绘图。 前言 之前的文章介绍了一些地图投影以及如何基本的用途。这篇文章介绍怎么在代码中实现,并添加一些矢量与栅格数据进行绘图。 完整代码及数据均开源,获取方式见文末。 数据来源 接下来介绍一下待会会用到的数据,仅是用作演示,所以随便找了一些。数据的详细来源与处理方法见文末。点数据有两份,一份为陆地样点分布,一份为海洋样点分布;面数据为大洲边界数据;栅格数据为陆地DEM数据和全球DEM数据。 投影实现 投影对比 先用cartopy的默认底图,生成一些简单的地图,对比一下看看效果。 其中Spilhaus投影绘制的时间较长,大致为2分钟。 Spilhaus和Orthographic投影以下仅是最简单版本,实际使用会再调整,之后会再单独写一篇。 projections.py PYTHON """ ------------------------------------------------------------------------------- @Author : zbhgis @Github : https://github.com/zbhgis @Description : generate some map-projection plots ------------------------------------------------------------------------------- """ import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature import time # 计时 start_time = time . perf_counter () # 设置投影名称与对应的投影 projections = [ ( "Mercator" , ccrs . Mercator ()), ( "Robinson" , ccrs . Robinson ()), ( "EqualEarth" , ccrs . EqualEarth ()), ( "GoodeHomolosine" , ccrs . InterruptedGoodeHomolosine ()), ( "SpilhausAdams" , ccrs . Spilhaus ()), ( "OrthographicNorth" , ccrs . Orthographic ( central_longitude = 0 , central_latitude = 90 )), ( "OrthographicEquator" , ccrs . Orthographic ( central_longitude = 0 , central_latitude = 0 )), ( "OrthographicSouth" , ccrs . Orthographic ( central_longitude = 0 , central_latitude =- 90 )), ] # 每个投影一张图片 for proj_name , proj in projections : fig = plt . figure ( figsize = ( 10 , 10 )) ax = fig . add_subplot ( 1 , 1 , 1 , projection = proj ) ax . set_global () ax . stock_img () ax . add_feature ( cfeature . COASTLINE , linewidth = 0.8 , edgecolor = "white" , alpha = 0.8 , ) ax . gridlines ( draw_labels = True , linewidth = 0.5 , color = "gray" , linestyle = "--" , alpha = 0.7 , ) ax . set_title ( proj_name , fontsize = 16 , pad = 10 ) print ( proj_name ) plt . tight_layout ( rect = [ 0 , 0 , 1 , 0.96 ]) plt . savefig ( f "./fig_res/world_maps_ { proj_name } .png" , dpi = 100 , bbox_inches = "tight" ) plt . close ( fig ) end_time = time . perf_counter () print ( end_time - start_time ) 打印结果 PLAIN Mercator Robinson EqualEarth GoodeHomolosine SpilhausAdams OrthographicNorth OrthographicEquator OrthographicSouth 159.37829679995775 绘制结果 Mercator Robinson EqualEarth Goode Spilhaus OrthographicNorth OrthographicEquator OrthographicSouth 添加数据 在上述代码的基础上,进一步添加数据进行制图。先通过rasterio包添加全球DEM数据与色带,然后再添加边界数据,最后分别添加样点数据(样点数据分布与对应值无实际含义,仅供演示)。 代码没啥难度,主要调整细节麻烦了一点,以下代码没有考虑科研风格,只是简单绘制了一下,之后会单独出一个系列来复现科研地图的。 以下是整理好的Python脚本,文末也提供了Jupyter Notebook格式的脚本,方便理解绘图过程与思路。 这行代码调整id即可绘制出对应的投影,大家根据需要调整即可,默认为Robinson投影。 PLAIN proj_name, proj_obj = projections[1] plot.py PYTHON """ ------------------------------------------------------------------------------- @Author : zbhgis @Github : https://github.com/zbhgis @Description : add some vector and raster data on map-projection plots ------------------------------------------------------------------------------- """ import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature import cartopy.io.shapereader as shpreader import rasterio import geopandas as gpd from matplotlib.lines import Line2D import numpy as np plt . rcParams [ "font.family" ] = "Arial" boundary_shp = "./data_res/boundary.shp" points_land_shp = "./data_res/points_land.shp" points_ocean_shp = "./data_res/points_ocean.shp" dem_tif = "./data_res/gebco_dem.tif" fig = plt . figure ( figsize = ( 14 , 10 ), dpi = 100 ) projections = [ ( "Mercator" , ccrs . Mercator ()), ( "Robinson" , ccrs . Robinson ()), ( "EqualEarth" , ccrs . EqualEarth ()), ( "GoodeHomolosine" , ccrs . InterruptedGoodeHomolosine ()), ( "SpilhausAdams" , ccrs . Spilhaus ()), ( "OrthographicNorth" , ccrs . Orthographic ( central_longitude = 0 , central_latitude = 90 )), ( "OrthographicEquator" , ccrs . Orthographic ( central_longitude = 0 , central_latitude = 0 )), ( "OrthographicSouth" , ccrs . Orthographic ( central_longitude = 0 , central_latitude =- 90 )), ] proj_name , proj_obj = projections [ 1 ] ax = fig . add_subplot ( 1 , 1 , 1 , projection = proj_obj ) ax . set_global () # 添加DEM数据 with rasterio . open ( dem_tif ) as src : dem_data = src . read ( 1 , masked = True ) left , bottom , right , top = src . bounds extent = [ left , right , bottom , top ] im = ax . imshow ( dem_data , extent = extent , transform = ccrs . PlateCarree (), origin = "upper" , cmap = "gist_earth" , vmin =- 6000 , vmax = 6000 , alpha = 0.8 , interpolation = "bilinear" , ) # 添加DEM色带 cbar = fig . colorbar ( im , ax = ax , orientation = "horizontal" , pad = 0.04 , aspect = 40 , shrink = 0.6 , ) cbar . ax . tick_params ( labelsize = 16 , labelcolor = "black" , length = 4 , ) cbar . set_label ( "Elevation(m)" , fontsize = 18 ) # 添加矢量边界数据 reader = shpreader . Reader ( boundary_shp ) boundary_feature = cfeature . ShapelyFeature ( reader . geometries (), ccrs . PlateCarree (), facecolor = "none" , edgecolor = "#928F8F" , linewidth = 2.0 , linestyle = "-" , ) ax . add_feature ( boundary_feature , zorder = 10 ) # 添加陆地点数据 gdf = gpd . read_file ( points_land_shp ) lons = gdf . geometry . x lats = gdf . geometry . y # 生成陆地点数据颜色 color_map_land = { 1 : "#E6F3FF" , 2 : "#B3D9FF" , 3 : "#80BFFF" , 4 : "#4DA6FF" , 5 : "#0066CC" , } colors = [ color_map_land . get ( level , "gray" ) for level in gdf [ "level" ]] # 绘制陆地点数据 ax . scatter ( lons , lats , s = 100 , c = colors , edgecolor = "black" , linewidth = 0.8 , alpha = 0.9 , transform = ccrs . PlateCarree (), zorder = 10 , ) # 添加陆地点图例 legend_elements_land = [ Line2D ( [ 0 ], [ 0 ], marker = "o" , linestyle = "none" , label = f "Level { l } " , markerfacecolor = color , markersize = 10 , markeredgecolor = "black" , ) for l , color in color_map_land . items () ] legend_land = ax . legend ( handles = legend_elements_land , loc = "lower left" , title = "Level" , title_fontsize = 18 , fontsize = 16 , frameon = True , edgecolor = "black" , facecolor = "white" , framealpha = 0.95 , ) legend_land . set_zorder ( 15 ) ax . add_artist ( legend_land ) # 相同方法再添加一次海洋点数据 gdf = gpd . read_file ( points_ocean_shp ) lons = gdf . geometry . x lats = gdf . geometry . y # 生成海洋点数据尺寸 size_map_ocean = { 1 : 50 , 2 : 100 , 3 : 150 , 4 : 200 , 5 : 250 , } sizes = [ size_map_ocean . get ( level , 0 ) for level in gdf [ "level" ]] # 绘制海洋点数据 ax . scatter ( lons , lats , s = sizes , c = "#9F9C9C" , edgecolor = "black" , linewidth = 0.8 , alpha = 0.9 , transform = ccrs . PlateCarree (), zorder = 10 , ) # 添加海洋点图例 legend_elements_ocean = [ Line2D ( [ 0 ], [ 0 ], marker = "o" , linestyle = "none" , label = f "Level { s } " , markerfacecolor = "#9F9C9C" , markersize = np . sqrt ( size ), markeredgecolor = "black" , ) for s , size in size_map_ocean . items () ] legend_ocean = ax . legend ( handles = legend_elements_ocean , loc = "lower right" , title = "Level" , title_fontsize = 18 , fontsize = 16 , frameon = True , edgecolor = "black" , facecolor = "white" , framealpha = 0.95 , ) legend_ocean . set_zorder ( 15 ) # 添加经纬度标签 gl = ax . gridlines ( draw_labels = False , linewidth = 0.5 , color = "gray" , alpha = 0.4 , linestyle = "--" , ) # 添加图名 ax . set_title ( proj_name , fontsize = 20 , pad = 10 ) plt . tight_layout () plt . savefig ( f "./fig_res/gebco_dem_ { proj_name } .png" , dpi = 100 , bbox_inches = "tight" , facecolor = "white" , ) print ( "ok" ) 打印结果 PLAIN ok 绘制结果 Mercator Robinson EqualEarth GoodeHomolosine Spilhaus OrthographicNorth OrthographicEquator OrthographicSouth 数据处理方法 接下来是数据的来源以及详细的处理方法,感兴趣的了解一下即可。 点数据 点数据来自于以下的2篇生物多样性文献: PLAIN Keck, F., Peller, T., Alther, R. et al. The global human impact on biodiversity. Nature 641, 395–400 (2025). https://doi.org/10.1038/s41586-025-08752-2 Carter, H.F., Bribiesca-Contreras, G. & Williams, S.T. Deep-sea-floor diversity in Asteroidea is shaped by competing processes across different latitudes and oceans. Nat Ecol Evol 9, 1910–1923 (2025). https://doi.org/10.1038/s41559-025-02808-2 在以下网址中中提供了所有数据: https://github.com/fkeck/metabeta/tree/main https://data.nhm.ac.uk/dataset/global-asteroidea-occurrence-data 下载文献的data.json和Global Asteroidea Occurrence Dataset.json后,通过以下Python代码将分别将数据简化为100条,并转为shp格式,保留坐标字段,并新建一个随机等级字段(用于配色)。 json2shp.py PYTHON """ ------------------------------------------------------------------------------- @Author : zbhgis @Github : https://github.com/zbhgis @Description : convert json to shapefile ------------------------------------------------------------------------------- """ import json import random import pandas as pd import geopandas as gpd from shapely.geometry import Point def json2shp ( json_path , output_shp_path , keep_count = 100 , lon_field = "Longitude" , lat_field = "Latitude" , crs = "EPSG:4326" , ): # 打开数据 with open ( json_path , "r" , encoding = "utf-8" ) as f : data = json . load ( f ) # 数据抽样 sampled_data = random . sample ( data , keep_count ) df = pd . DataFrame ( sampled_data ) df = df [[ lon_field , lat_field ]] # 字段重命名 df = df . rename ( columns = { lon_field : "lon" , lat_field : "lat" }) df [ "lon" ] = pd . to_numeric ( df [ "lon" ], errors = "coerce" ) df [ "lat" ] = pd . to_numeric ( df [ "lat" ], errors = "coerce" ) # 颜色字段 df [ "level" ] = [ random . randint ( 1 , 5 ) for _ in range ( len ( df ))] # 生成gdf geometry = [ Point ( xy ) for xy in zip ( df [ "lon" ], df [ "lat" ])] gdf = gpd . GeoDataFrame ( df . drop ( columns = [ "lon" , "lat" ]), geometry = geometry , crs = crs , ) gdf . to_file ( output_shp_path , encoding = "utf-8" ) if __name__ == "__main__" : json_file = "./data_origin/data.json" shp_file = "./data_res/points_land.shp" json2shp ( json_path = json_file , output_shp_path = shp_file , keep_count = 100 , lon_field = "Longitude" , lat_field = "Latitude" , crs = "EPSG:4326" , ) json_file = "./data_origin/resource.json" shp_file = "./data_res/points_ocean.shp" json2shp ( json_path = json_file , output_shp_path = shp_file , keep_count = 100 , lon_field = "Long" , lat_field = "Lat" , crs = "EPSG:4326" , ) print ( "OK" ) 打印结果 PLAIN OK 面数据 面数据是一份很早之前在网上下载的大洲边界矢量数据,通过以下Python代码检查一下数据。 check_shp.py PYTHON """ ------------------------------------------------------------------------------- @Author : zbhgis @Github : https://github.com/zbhgis @Description : check and copy shapefile ------------------------------------------------------------------------------- """ import geopandas as gpd import os import shutil def check_file ( shp_path ): gdf = gpd . read_file ( shp_path ) if gdf . crs is None : print ( "未定义坐标系" ) elif gdf . crs . to_epsg () == 4326 : print ( "EPSG:4326" ) elif gdf . crs . to_epsg () is not None : print ( f "EPSG: { gdf . crs . to_epsg () } " ) def copy_shapefile ( shp_path , output_folder , new_base_name ): base_dir = os . path . dirname ( shp_path ) base_name = os . path . splitext ( os . path . basename ( shp_path ))[ 0 ] extensions = [ ".shp" , ".shx" , ".dbf" , ".prj" , ".cpg" , ".sbn" , ".sbx" , ".shp.xml" ] copied = 0 for ext in extensions : src_file = os . path . join ( base_dir , base_name + ext ) if os . path . exists ( src_file ): dst_file = os . path . join ( output_folder , new_base_name + ext ) shutil . copy2 ( src_file , dst_file ) copied += 1 if copied > 0 : print ( f "成功复制" ) else : print ( "复制失败" ) if __name__ == "__main__" : shp = "./data_origin/continent.shp" target_folder = "./data_res" check_file ( shp ) copy_shapefile ( shp , target_folder , "boundary" ) 打印结果 PLAIN EPSG:4326 成功复制 栅格数据 栅格数据是通过GEE下载的DEM数据,通过以下js代码重采样为10km分辨率并下载至本地。 陆地DEM下载 数据介绍: https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_DEM_GLO30 cop_download.js JAVASCRIPT var dataset = ee . ImageCollection ( "COPERNICUS/DEM/GLO30" ); var elevation = dataset . select ( "DEM" ). mosaic (); var elevationVis = { min : 0.0 , max : 1000.0 , palette : [ "0000ff" , "00ffff" , "ffff00" , "ff0000" , "ffffff" ], }; Map . setCenter ( - 6.746 , 46.529 , 4 ); Map . addLayer ( elevation , elevationVis , "DEM" ); Export . image . toDrive ({ crs : "EPSG:4326" , image : elevation , description : "WORLD_Elevation" , scale : 10000 , maxPixels : 1e13 , }); 全球DEM下载 数据介绍: https://gee-community-catalog.org/projects/gebco/ gebco_download.js JAVASCRIPT var dataset = ee . ImageCollection ( "projects/sat-io/open-datasets/gebco/gebco_grid" , ); var elevation = dataset . select ( "b1" ). mosaic (); var elevationVis = { min : - 7000.0 , max : 5000.0 , palette : [ "0000ff" , "00ffff" , "ffff00" , "ff0000" , "ffffff" ], }; Map . setCenter ( - 37.62 , 25.8 , 2 ); Map . addLayer ( elevation , elevationVis , "b1" ); Export . image . toDrive ({ crs : "EPSG:4326" , image : elevation , description : "GEBCO_Elevation" , scale : 10000 , maxPixels : 1e13 , }); 写在最后 完整代码及相关数据文件会在以下github仓库中开源,若有帮助欢迎点个star,不胜感激。 https://github.com/zbhgis/Projects 或者在微信公众号后台回复关键词“ 代码获取 ”即可获取百度网盘链接,找到对应名称的文件夹即可(百度网盘链接可能隔几天才会同步)。 代码中使用了很多相对路径,建议获取的时候下载完整文件夹。 该系列下一篇会再对Spilhaus和Orthographic投影绘制进行补充。 如有问题,欢迎添加个人微信交流。 --- ## 顶刊中的全球地图投影(二)-特殊投影 - URL: https://geosciplot.zbhgis.com/guide/map-projection-special/ - 日期: 2026-03-03 - 摘要: 之前简单地介绍一下常用地图投影的区别,特点,作图参考,以及各自的用途。这篇文章主要介绍一些较少用,但可能会见到的全球地图投影,以及一些特殊的地图投影。 前言 之前简单地介绍一下常用地图投影的区别,特点,作图参考,以及各自的用途。这篇文章主要介绍一些较少用,但可能会见到的全球地图投影,以及一些特殊的地图投影。 特殊地图投影汇总 以下地图投影比如Goode,Spilhaus,Orthographic这三类投影是比较特别的投影,其中Goode Homolosine投影是把海洋给切开,保证陆地的完整性;Spilhaus-Adams则相反,是突出海洋部分;Orthographic投影就是正射投影,但是角度不同投影结果也有很大差别;剩余的Gall-Peters,Lambert Cylindrical,Winkel Tripel和Wagner IV这四类投影用得比较少,但是在期刊中也有一小部分文章使用,和之前介绍的常用投影差别不大,就不再过多介绍。具体不同投影的差别可以在以下网站查询对比或者直接问AI大模型。 https://map-projections.net/projections-list.php 接下来是整理的7个特殊的或较少使用的全球地图投影(没有进行客观的数据统计,仅仅是结合经验和部分搜索结果得出)。 名称 类型 属性 主要特点与用途 Goode/ Goode Homolosine 伪圆柱 等积 突出陆地,减少扭曲,面积准确 Spilhaus-Adams / Spilhaus World Ocean Map in a Square 多边形 折衷 突出海洋连续性,陆地压缩 Orthographic / Azimuthal / / 太空视角,大多为半球视图或极地视图,三维地球感强 Gall-Peters / Gall Orthographic / Peters projection 圆柱 等积 矩形地图,面积准确 Lambert Cylindrical / Lambert Cylindrical Equal Area 圆柱 等积 矩形呈现,面积准确 Winkel Tripel 伪圆柱 折衷 畸变低,保证视觉平衡 Wagner IV 伪圆柱 等积 经线椭圆弧,侧边平滑,面积精确 顶刊中的地图 Goode Homolosine 示例1 期刊:Nature 来源: https://doi.org/10.1038/s41586-022-04664-7 图片: 示例2 期刊:Nature Communications 来源: https://doi.org/10.1038/s41467-025-64438-3 图片: Spilhaus-Adams 示例1 期刊:Science Advances 来源: https://doi.org/10.1126/sciadv.abo6672 图片: 示例2 期刊:Nature 来源: https://doi.org/10.1038/s41586-024-07247-w 图片: Orthographic/Azimuthal 示例1 期刊:Nature Climate Change 来源: https://doi.org/10.1038/s41558-025-02282-5 图片: 示例2 期刊:Nature 来源: https://doi.org/10.1038/s41586-021-03706-w 图片: Gall-Peters 示例1 期刊:Nature Sustainability 来源: https://doi.org/10.1038/s41893-022-00965-x 图片: 示例2 期刊:Nature Ecology & Evolution 来源: https://doi.org/10.1038/s41559-017-0299-z 图片: Lambert Cylindrical 示例1 期刊:Nature Communications 来源: https://doi.org/10.1038/s41467-023-40053-y 图片: 示例2 期刊:Nature Communications 来源: https://doi.org/10.1038/s41467-025-61477-8 图片: Winkel Tripel 示例1 期刊:Science Advances 来源: https://doi.org/10.1126/sciadv.adi5502 图片: 示例2 期刊:Nature Geoscience 来源: https://doi.org/10.1038/s41561-018-0262-x 图片: Wagner IV 示例1 期刊:Nature Ecology & Evolution 来源: https://doi.org/10.1038/s41559-024-02599-y 图片: 示例2 期刊:Nature Communications 来源: https://doi.org/10.1038/s41467-023-39954-9 图片: 不同投影的用途 Goode,Spilhaus,Orthographic这三类投影主要是展示数据的时候,用于突出全球视角下的某个特殊区位(陆地,海洋,或者指定区域),之后进行复现这三类地图投影时,就能感受到这些地图投影的不同;文中后四类投影均属于等面积投影,就不再展开。 写在最后 “顶刊全球地图投影”系列会更新4~8篇,主要内容是不同地图投影的基本介绍,绘图参考,以及实现方法。 下一篇会介绍一些投影网站的使用或者代码复现。 --- ## 顶刊中的全球地图投影(一)-常用投影 - URL: https://geosciplot.zbhgis.com/guide/map-projection-basics/ - 日期: 2026-03-02 - 摘要: 花时间整理了一些世界地图投影与代码复现,以及顶刊中对应的地图。这篇文章先简单地介绍一下常用地图投影的区别,特点,作图参考,以及各自的用途。 前言 花时间整理了一些世界地图投影与代码复现,以及顶刊中对应的地图。这篇文章先简单地介绍一下常用地图投影的区别,特点,作图参考,以及各自的用途。 地图投影的区别 以下是常用的地图投影的主要区别 圆柱与伪圆柱投影的异同: 圆柱(Cylindrical)投影的经线全部为直线且平行,形成矩形地图网格,导致高纬极端扭曲,如Mercator、Behrmann等; 伪圆柱(Pseudocylindrical)投影的经线除中央直线外均为对称弯曲曲线,整体变形更均匀自然,为椭圆或圆润桶形,如Robinson、Mollweide等。 等角,等积,折衷投影的异同: 等角 (Conformal)投影保留局部角度和形状准确,但牺牲面积,导致高纬严重夸大,如Mercato等; 等积(Equal-Area)投影保留相对面积比例正确,形状不够准确,如Equal Earth等; 折衷(Compromise)投影则在面积、形状、角度间寻求平衡以最小化整体畸变,无单一属性完美保留,但视觉最自然,如Robinson等。 常用地图投影汇总 以下地图投影比如Mercator,Hammer等只是一类投影的简称,他们在自身的投影基础上会有很多衍生投影,比如Mercator投影是正轴等角圆柱投影,其衍生投影有Web Mercator(比如网页中的瓦片地图)和Transverse Mercator(比如UTM分带系统)等。具体不同投影的差别可以在以下网站查询对比或者直接问AI大模型。 https://map-projections.net/projections-list.php 接下来是整理的7个常用的全球地图投影(没有进行客观的数据统计,仅仅是结合经验和部分搜索结果得出)。 名称 类型 属性 主要特点 Mercator / Mercator Cylindrical 圆柱 等角 保持角度/形状准确,航海经典;但高纬度面积严重夸大 Robinson / Robinson Pseudocylindrical 伪圆柱 折衷 视觉平衡好,对于面积和形状均有取舍 Equal Earth / Equal Earth Equal-Area Pseudocylindrical 伪圆柱 等积 形状类似Robinson但严格等积,美观且面积准确 Mollweide / Mollweide Equal-Area 伪圆柱 (椭圆形) 等积 椭圆形(2:1轴比),压缩极区,面积准确 Eckert IV / Eckert IV Equal-Area Pseudocylindrical 伪圆柱 等积 侧边经线半圆,拐角平滑,面积准确 Behrmann / Behrmann Equal-Area Cylindrical 圆柱 等积 标准纬线±30°,压缩极区,面积准确 Hammer / Hammer Equal-Area / Hammer-Aitoff 伪圆柱 (椭圆形) 等积 类似Mollweide但更圆润,面积精确;适合小比例全球地图,扭曲较均匀 顶刊地图投影参考 整理了Nature和Science系列期刊(主要是Nature系列)上的对应投影的一些地图的呈现结果,供各位参考。 Mercator 示例1 期刊:Nature Ecology & Evolution 来源: https://doi.org/10.1038/s41559-025-02955-6 图片: 示例2 期刊:Nature 来源: https://doi.org/10.1038/s41586-022-05413-6 图片: Robinson 示例1 期刊:Nature Communications 来源: https://doi.org/10.1038/s41467-023-37027-5 图片: 示例2 期刊:Nature Ecology & Evolution 来源: https://doi.org/10.1038/s41559-023-02071-3 图片: Equal Earth 示例1 期刊:Nature Communications 来源: https://doi.org/10.1038/s41467-025-57054-8 图片: 示例1 期刊:Nature Communications 来源: https://doi.org/10.1038/s41467-025-64449-0 图片: Mollweide 示例1 期刊:Nature 来源: https://doi.org/10.1038/s41586-021-03371-z 图片: 示例2 期刊:Nature Climate Change 来源: https://doi.org/10.1038/s41558-025-02498-5 图片: Eckert IV 示例1 期刊:Nature Climate Change 来源: https://doi.org/10.1038/s41558-025-02337-7 图片: 示例2 期刊:Nature Ecology & Evolution 来源: https://doi.org/10.1038/s41559-024-02599-y 图片: Behrmann 示例1 期刊:Nature Communications 来源: https://doi.org/10.1038/s41467-021-27186-8 图片: 示例2 期刊:Nature Ecology & Evolution 来源: https://doi.org/10.1038/s41559-024-02450-4 图片: Hammer 示例1 期刊:Nature Climate Change 来源: https://doi.org/10.1038/nclimate2554 图片: 示例2 期刊:Nature Astronomy 来源: https://doi.org/10.1038/s41550-023-02130-6 图片: 不同投影的用途 这些投影在样本点展示的时候基本都能用,但是Robinson折衷投影在视觉上最为协调,所以主要在展示研究区或者样点的时候使用;而在全球数据处理的时候,投影可能会导致同一地区的面积在数据中相差较大,所以在数据处理的时候,主要使用Equal Earth,Mollweide这些等面积的投影,减少偏差;至于等面积投影之间具体选择哪个,笔者认为没有太大差别,很多时候是根据手上的数据投影再进一步选择;Hammer投影貌似是在天文领域用得比较多,所以也一并整理。 写在最后 “顶刊全球地图投影”系列会更新4~8篇,主要内容是不同地图投影的基本介绍,绘图参考,以及实现方法。 下一篇会介绍一些特殊的全球地图投影。 ---