Построение объектов Natural Earth на специальной проекции
Я пытаюсь сделать некоторые данные по морскому льду. Данные доставляются в сетку EASE-North, файл примера (HDF4) можно загрузить по адресу:
ftp://n4ftl01u.ecs.nasa.gov/SAN/OTHR/NISE.004/2013.09.30/
Я создал собственный класс проекции для EASE-Grid, он, кажется, работает (береговые линии хорошо совпадают с данными).
Когда я пытаюсь добавить функцию Natural Earth, она возвращает пустую фигуру Matplotlib.
import gdal
import cartopy
# projection class
class EASE_North(cartopy.crs.Projection):
def __init__(self):
# see: http://www.spatialreference.org/ref/epsg/3408/
proj4_params = {'proj': 'laea',
'lat_0': 90.,
'lon_0': 0,
'x_0': 0,
'y_0': 0,
'a': 6371228,
'b': 6371228,
'units': 'm',
'no_defs': ''}
super(EASE_North, self).__init__(proj4_params)
@property
def boundary(self):
coords = ((self.x_limits[0], self.y_limits[0]),(self.x_limits[1], self.y_limits[0]),
(self.x_limits[1], self.y_limits[1]),(self.x_limits[0], self.y_limits[1]),
(self.x_limits[0], self.y_limits[0]))
return cartopy.crs.sgeom.Polygon(coords).exterior
@property
def threshold(self):
return 1e5
@property
def x_limits(self):
return (-9000000, 9000000)
@property
def y_limits(self):
return (-9000000, 9000000)
# read the data
ds = gdal.Open('D:/NISE_SSMISF17_20130930.HDFEOS')
# this loads the layers for both hemispheres
data = np.array([gdal.Open(name, gdal.GA_ReadOnly).ReadAsArray()
for name, descr in ds.GetSubDatasets() if 'Extent' in name])
ds = None
# mask anything other then sea ice
sea_ice_concentration = np.ma.masked_where((data < 1) | (data > 100), data, 0)
# plot
lim = 3000000
fig, ax = plt.subplots(figsize=(8,8),subplot_kw={'projection': EASE_North(), 'xlim': [-lim,lim], 'ylim': [-lim,lim]})
land = cartopy.feature.NaturalEarthFeature(
category='physical',
name='land',
scale='50m',
facecolor='#dddddd',
edgecolor='none')
#ax.add_feature(land)
ax.coastlines()
# from the metadata in the HDF
extent = [-9036842.762500, 9036842.762500, -9036842.762500, 9036842.762500]
ax.imshow(sea_ice_concentration[0,:,:], cmap=plt.cm.Blues, vmin=1,vmax=100,
interpolation='none', origin='upper', extent=extent, transform=EASE_North())
Сценарий выше работает нормально и дает такой результат:
Но когда я раскомментирую ax.add_feature(land)
он завершается безо всякой ошибки, только возвращает пустую цифру. Я что-то упускаю очевидное?
Вот записная книжка IPython: http://nbviewer.ipython.org/6779935
Моя сборка Cartopy - версия 0.9 с веб-сайта Кристофа Гольке (спасибо!).
редактировать:
Попытка сохранить рисунок выдает исключение:
fig.savefig(r'D:\test.png')
C:\Python27\Lib\site-packages\shapely\speedups\_speedups.pyd in shapely.speedups._speedups.geos_linearring_from_py (shapely/speedups/_speedups.c:2270)()
ValueError: A LinearRing must have at least 3 coordinate tuples
Изучение "земли" cartopy.feature
не выявляет никаких проблем, все полигоны проходят .isvalid()
и все кольца (ext en int) состоят из 4 или более кортежей. Таким образом, форма ввода не является проблемой (и прекрасно работает в PlateCaree()).
Может быть, некоторые кольца (как в южном полушарии) становятся "поврежденными" после преобразования в EASE_North?
edit2:
Когда я удаляю встроенные элементы NE и загружаю тот же шейп-файл (но с любым размером ниже 40N), он работает. Так что это похоже на проблему перепроектирования.
for state in shpreader.Reader(r'D:\ne_50m_land_clipped.shp').geometries():
ax.add_geometries([state], cartopy.crs.PlateCarree(),facecolor='#cccccc', edgecolor='#cccccc')
1 ответ
Я бы сказал, что это ошибка. я догадываюсь add_feature
обновляет matplotlib viewLim, и в результате изображение увеличивается до крошечной области (которая выглядит белой, если вы не уменьшите масштаб).
От всей души я думаю, что базовое поведение улучшилось в matplotlib, но в cartopy еще не используется новый расчет viewLim. А пока я бы предложил установить экстенты вашей карты вручную с помощью:
ax.set_extent(extent, transform=EASE_North())
НТН