以太平洋为中心的世界地图上的等高线图
Contour plot on a world map centered at the Pacific
我正在尝试在世界地图上绘制一些数据,这些数据可以以大西洋附近(即 180°W–180°E)或太平洋(即 0°–360°)为中心。这是程序(带有虚构数据):
import argparse
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
parser = argparse.ArgumentParser()
parser.add_argument('--center', choices=['atlantic', 'pacific'], default='atlantic')
parser.add_argument('--outfile', default='plot.png')
args = parser.parse_args()
lat = np.linspace(-89.95, 89.95, 1800)
if args.center == 'atlantic':
lon = np.linspace(-179.95, 179.95, 3600)
clon = 0
else:
lon = np.linspace(0.05, 359.95, 3600)
clon = 180
x, y = np.meshgrid(lon, lat)
z = np.sin(x / 180 * np.pi) * np.sin(y / 180 * np.pi)
fig = plt.figure(figsize=(21, 7))
crs = ccrs.PlateCarree(central_longitude=clon)
ax = plt.axes(projection=crs)
ax.coastlines(resolution='110m', color='white', linewidth=2)
gl = ax.gridlines(crs=crs, draw_labels=True, linewidth=1, color='black', linestyle='--')
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
gl.xlabel_style = {'size': 16, 'color': 'black'}
gl.ylabel_style = {'size': 16, 'color': 'black'}
plt.contourf(x, y, z, cmap='RdYlBu_r')
cb = plt.colorbar(ax=ax, orientation='vertical', pad=0.02, aspect=16, shrink=0.8)
cb.ax.tick_params(labelsize=16)
fig.savefig(args.outfile, bbox_inches='tight', pad_inches=0.1)
但是,当我从--center=atlantic
切换到--center=pacific
时,只有海岸线移动,而X轴和数据没有移动,导致绘图不一致。 (我虚构的数据,北美应该是蓝色的,亚洲应该是红色的。)
--center=atlantic
:
--center=pacific
:
如何绘制以太平洋为中心的正确地块?
看来我需要进行以下更改:
- 有一个普通的
PlateCarree
对象(除了现有的设置了 central_longitude
的对象)并在除调用 plt.axes
之外的所有情况下使用它。 (我不明白为什么,但我发现它有效。)
- 添加对
ax.set_extent
的调用,也使用原版 PlateCarree
对象。
- 在
plt.contourf
中使用 transform
,也使用原版 PlateCarree
对象。
这是与原始代码的不同之处:
@@ -23,0 +24 @@
+crs0 = ccrs.PlateCarree()
@@ -25,0 +27 @@
+ax.set_extent([lon[0], lon[-1], lat[0], lat[-1]], crs=crs0)
@@ -28 +30 @@
-gl = ax.gridlines(crs=crs, draw_labels=True, linewidth=1, color='black', linestyle='--')
+gl = ax.gridlines(crs=crs0, draw_labels=True, linewidth=1, color='black', linestyle='--')
@@ -34 +36 @@
-plt.contourf(x, y, z, cmap='RdYlBu_r')
+plt.contourf(x, y, z, cmap='RdYlBu_r', transform=crs0)
这会产生 180°W
和 180°E
相互覆盖。作为快速修复,我这样做了:
import matplotlib.ticker as mticker
# Fix LONGITUDE_FORMATTER so that either +180 or -180 returns just '180°',
# instead of '180°E' or '180°W'.
LONGITUDE_FORMATTER_NEW = mticker.FuncFormatter(
lambda v, pos: '180\u00B0' if abs(v) == 180 else LONGITUDE_FORMATTER.func(v, pos)
)
以便相同的字符串 180°
在同一位置彼此重叠,从而最大限度地减少问题的视觉效果。
(LONGITUDE_FORMATTER
也无法正确处理超出 [−180, +180] 的任何内容,但我选择不在这里讨论。)
结果如下:
--center=atlantic
:
--center=pacific
:
我正在尝试在世界地图上绘制一些数据,这些数据可以以大西洋附近(即 180°W–180°E)或太平洋(即 0°–360°)为中心。这是程序(带有虚构数据):
import argparse
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
parser = argparse.ArgumentParser()
parser.add_argument('--center', choices=['atlantic', 'pacific'], default='atlantic')
parser.add_argument('--outfile', default='plot.png')
args = parser.parse_args()
lat = np.linspace(-89.95, 89.95, 1800)
if args.center == 'atlantic':
lon = np.linspace(-179.95, 179.95, 3600)
clon = 0
else:
lon = np.linspace(0.05, 359.95, 3600)
clon = 180
x, y = np.meshgrid(lon, lat)
z = np.sin(x / 180 * np.pi) * np.sin(y / 180 * np.pi)
fig = plt.figure(figsize=(21, 7))
crs = ccrs.PlateCarree(central_longitude=clon)
ax = plt.axes(projection=crs)
ax.coastlines(resolution='110m', color='white', linewidth=2)
gl = ax.gridlines(crs=crs, draw_labels=True, linewidth=1, color='black', linestyle='--')
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
gl.xlabel_style = {'size': 16, 'color': 'black'}
gl.ylabel_style = {'size': 16, 'color': 'black'}
plt.contourf(x, y, z, cmap='RdYlBu_r')
cb = plt.colorbar(ax=ax, orientation='vertical', pad=0.02, aspect=16, shrink=0.8)
cb.ax.tick_params(labelsize=16)
fig.savefig(args.outfile, bbox_inches='tight', pad_inches=0.1)
但是,当我从--center=atlantic
切换到--center=pacific
时,只有海岸线移动,而X轴和数据没有移动,导致绘图不一致。 (我虚构的数据,北美应该是蓝色的,亚洲应该是红色的。)
--center=atlantic
:--center=pacific
:
如何绘制以太平洋为中心的正确地块?
看来我需要进行以下更改:
- 有一个普通的
PlateCarree
对象(除了现有的设置了central_longitude
的对象)并在除调用plt.axes
之外的所有情况下使用它。 (我不明白为什么,但我发现它有效。) - 添加对
ax.set_extent
的调用,也使用原版PlateCarree
对象。 - 在
plt.contourf
中使用transform
,也使用原版PlateCarree
对象。
这是与原始代码的不同之处:
@@ -23,0 +24 @@
+crs0 = ccrs.PlateCarree()
@@ -25,0 +27 @@
+ax.set_extent([lon[0], lon[-1], lat[0], lat[-1]], crs=crs0)
@@ -28 +30 @@
-gl = ax.gridlines(crs=crs, draw_labels=True, linewidth=1, color='black', linestyle='--')
+gl = ax.gridlines(crs=crs0, draw_labels=True, linewidth=1, color='black', linestyle='--')
@@ -34 +36 @@
-plt.contourf(x, y, z, cmap='RdYlBu_r')
+plt.contourf(x, y, z, cmap='RdYlBu_r', transform=crs0)
这会产生 180°W
和 180°E
相互覆盖。作为快速修复,我这样做了:
import matplotlib.ticker as mticker
# Fix LONGITUDE_FORMATTER so that either +180 or -180 returns just '180°',
# instead of '180°E' or '180°W'.
LONGITUDE_FORMATTER_NEW = mticker.FuncFormatter(
lambda v, pos: '180\u00B0' if abs(v) == 180 else LONGITUDE_FORMATTER.func(v, pos)
)
以便相同的字符串 180°
在同一位置彼此重叠,从而最大限度地减少问题的视觉效果。
(LONGITUDE_FORMATTER
也无法正确处理超出 [−180, +180] 的任何内容,但我选择不在这里讨论。)
结果如下:
--center=atlantic
:--center=pacific
: