def lookup_map_feature(feature_name): """Get a Cartopy map feature based on a name.""" import cartopy.feature as cfeature from . import cartopy_utils name = feature_name.upper() try: feat = getattr(cfeature, name) scaler = cfeature.AdaptiveScaler('110m', (('50m', 50), ('10m', 15))) except AttributeError: feat = getattr(cartopy_utils, name) scaler = cfeature.AdaptiveScaler('20m', (('5m', 5), ('500k', 1))) return feat.with_scale(scaler)
def _layer_features(self): """Iterate over all map features and return as Cartopy objects. Handle converting names of maps to auto-scaling map features. """ for item in self.layers: if is_string_like(item): item = item.upper() try: scaler = cfeature.AdaptiveScaler('110m', (('50m', 50), ('10m', 15))) feat = getattr(cfeature, item).with_scale(scaler) except AttributeError: scaler = cfeature.AdaptiveScaler('20m', (('5m', 5), ('500k', 1))) feat = getattr(cartopy_utils, item).with_scale(scaler) else: feat = item yield feat
def plot(self, variable=None, vmin=None, vmax=None, filename=None, title=None, buffer=1, lscale='auto'): """Plot geographical coverage of reader.""" fig = plt.figure() if self.global_coverage(): lonmin=-180 lonmax=180 latmin=-89 latmax=89 else: corners = self.xy2lonlat([self.xmin, self.xmin, self.xmax, self.xmax], [self.ymax, self.ymin, self.ymax, self.ymin]) lonmin = np.min(corners[0]) - buffer*2 lonmax = np.max(corners[0]) + buffer*2 latmin = np.min(corners[1]) - buffer latmax = np.max(corners[1]) + buffer # Initialise map if not self.global_coverage(): # Stereographic projection centred on domain, if small domain x0 = (self.xmin + self.xmax) / 2 y0 = (self.ymin + self.ymax) / 2 lon0, lat0 = self.xy2lonlat(x0, y0) sp = ccrs.Stereographic(central_longitude=lon0, central_latitude=lat0) latmax = np.maximum(latmax, lat0) latmin = np.minimum(latmin, lat0) else: # Global map if reader domain is large sp = ccrs.Mercator() ax = fig.add_subplot(1, 1, 1, projection=sp) if lscale == 'auto': # Custom lscale - this should be generalized to Basemodel also s = cfeature.AdaptiveScaler('coarse', (('low', 100), ('intermediate', 20), ('high', 5), ('full', 1))) lscale = s.scale_from_extent([lonmin, lonmax, latmin, latmax]) # GSHHS coastlines f = cfeature.GSHHSFeature(scale=lscale, levels=[1]) f._geometries_cache = {} ax.add_geometries( #f.intersecting_geometries([lonmin, lonmax, latmin, latmax]), f.geometries(), ccrs.PlateCarree(), facecolor=cfeature.COLORS['land'], edgecolor='black') gl = ax.gridlines(ccrs.PlateCarree()) gl.top_labels = False # Get boundary if self.global_coverage(): lon = np.array([-180, 180, 180, -180, -180]) lat = np.array([-89, -89, 89, 89, -89]) else: npoints = 10 # points per side x = np.array([]) y = np.array([]) x = np.concatenate((x, np.linspace(self.xmin, self.xmax, npoints))) y = np.concatenate((y, [self.ymin]*npoints)) x = np.concatenate((x, [self.xmax]*npoints)) y = np.concatenate((y, np.linspace(self.ymin, self.ymax, npoints))) x = np.concatenate((x, np.linspace(self.xmax, self.xmin, npoints))) y = np.concatenate((y, [self.ymax]*npoints)) x = np.concatenate((x, [self.xmin]*npoints)) y = np.concatenate((y, np.linspace(self.ymax, self.ymin, npoints))) # from x/y vectors create a Patch to be added to map lon, lat = self.xy2lonlat(x, y) lat[lat>89] = 89. lat[lat<-89] = -89. p = sp.transform_points(ccrs.PlateCarree(), lon, lat) xsp = p[:, 0] ysp = p[:, 1] if variable is None: boundary = Polygon(list(zip(xsp, ysp)), alpha=0.5, ec='k', fc='b', zorder=100) ax.add_patch(boundary) if self.global_coverage(): ax.set_global() else: buf = (xsp.max()-xsp.min())*.1 # Some whitespace around polygon ax.set_extent([xsp.min()-buf, xsp.max()+buf, ysp.min()-buf, ysp.max()+buf], crs=sp) if title is None: plt.title(self.name) else: plt.title(title) plt.xlabel('Time coverage: %s to %s' % (self.start_time, self.end_time)) if variable is not None: rx = np.array([self.xmin, self.xmax]) ry = np.array([self.ymin, self.ymax]) if variable in self.derived_variables: data = self.get_variables(self.derived_variables[variable], self.start_time, rx, ry) self.__calculate_derived_environment_variables__(data) else: data = self.get_variables(variable, self.start_time, rx, ry) rx, ry = np.meshgrid(data['x'], data['y']) rx = np.float32(rx) ry = np.float32(ry) rlon, rlat = self.xy2lonlat(rx, ry) data[variable] = np.ma.masked_invalid(data[variable]) if data[variable].ndim > 2: logger.warning('Ensemble data, plotting only first member') data[variable] = data[variable][0,:,:] if self.global_coverage(): mappable = ax.pcolormesh(rlon, rlat, data[variable], vmin=vmin, vmax=vmax, transform=ccrs.PlateCarree(), shading='nearest') else: p = sp.transform_points(ccrs.PlateCarree(), rlon, rlat) mapx = p[:,:,0] mapy = p[:,:,1] mappable = ax.pcolormesh(mapx, mapy, data[variable], vmin=vmin, vmax=vmax, shading='nearest') cbar = fig.colorbar(mappable, orientation='horizontal', pad=.05, aspect=30, shrink=.4) cbar.set_label(variable) try: # Activate figure zooming mng = plt.get_current_fig_manager() mng.toolbar.zoom() except: pass if filename is not None: plt.savefig(filename) plt.close() else: plt.show()
# but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with cartopy. If not, see <https://www.gnu.org/licenses/>. from __future__ import (absolute_import, division, print_function) import cartopy.feature as cfeature small_extent = (-6, -8, 56, 59) medium_extent = (-20, 20, 20, 60) large_extent = (-40, 40, 0, 80) auto_scaler = cfeature.AdaptiveScaler('110m', (('50m', 50), ('10m', 15))) auto_land = cfeature.NaturalEarthFeature('physical', 'land', auto_scaler) class TestFeatures(object): def test_change_scale(self): # Check that features can easily be retrieved with a different # scale. new_lakes = cfeature.LAKES.with_scale('10m') assert new_lakes.scale == '10m' assert new_lakes.kwargs == cfeature.LAKES.kwargs assert new_lakes.category == cfeature.LAKES.category assert new_lakes.name == cfeature.LAKES.name def test_scale_from_extent(self):