def test_polygon_interiors(): ax = plt.subplot(211, projection=ccrs.PlateCarree()) ax.coastlines() ax.set_global() # XXX could be the default??? pth = Path([[0, 45], [60, 45], [60, -45], [0, -45], [0, -45], [10, 20], [10, -20], [40, -20], [40, 20], [10, -20]], [1, 2, 2, 2, 79, 1, 2, 2 , 2, 79]) patches_native = [] patches = [] for geos in cpatch.path_to_geos(pth): for pth in cpatch.geos_to_path(geos): patches.append(mpatches.PathPatch(pth)) # buffer by 10 degrees (leaves a small hole in the middle) geos_buffered = geos.buffer(10) for pth in cpatch.geos_to_path(geos_buffered): patches_native.append(mpatches.PathPatch(pth)) collection = PatchCollection(patches_native, facecolor='red', alpha=0.4, transform=ax.projection ) ax.add_collection(collection) collection = PatchCollection(patches, facecolor='yellow', alpha=0.4, transform=ccrs.Geodetic() ) ax.add_collection(collection) # test multiple interior polygons ax = plt.subplot(212, projection=ccrs.PlateCarree(), xlim=[-5, 15], ylim=[-5, 15]) ax.coastlines() exterior = np.array(shapely.geometry.box(0, 0, 12, 12).exterior.coords) interiors = [ np.array(shapely.geometry.box(1, 1, 2, 2, ccw=False).exterior.coords), np.array(shapely.geometry.box(1, 8, 2, 9, ccw=False).exterior.coords), ] poly = shapely.geometry.Polygon(exterior, interiors) patches = [] for pth in cpatch.geos_to_path(poly): patches.append(mpatches.PathPatch(pth)) collection = PatchCollection(patches, facecolor='yellow', alpha=0.4, transform=ccrs.Geodetic() ) ax.add_collection(collection)
def transform_path_non_affine(self, path): bypass = self.source_projection == self.target_projection if bypass: projection = self.source_projection if isinstance(projection, ccrs._CylindricalProjection): x = path.vertices[:, 0] x_limits = projection.x_limits bypass = x.min() >= x_limits[0] and x.max() <= x_limits[1] if bypass: return path if path.vertices.shape == (1, 2): return mpath.Path(self.transform(path.vertices)) transformed_geoms = [] for geom in patch.path_to_geos(path): transformed_geoms.append(self.target_projection.project_geometry(geom, self.source_projection)) if not transformed_geoms: return mpath.Path(numpy.empty([0, 2])) else: paths = patch.geos_to_path(transformed_geoms) if not paths: return mpath.Path(numpy.empty([0, 2])) points, codes = zip(*[patch.path_segments(path, curves=False, simplify=False) for path in paths]) return mpath.Path(numpy.concatenate(points, 0), numpy.concatenate(codes))
def gshhs_line(self, outline_color='k', domain=None, resolution='low', **kwargs): # domain is a shapely geometry (Polygon or MultiPolygon) import cartopy.gshhs as gshhs # import cartopy.spherical as spherical from matplotlib.collections import PatchCollection, LineCollection paths = [] projection = self.projection if domain is None: domain = self.map_domain(ccrs.PlateCarree()) for points in gshhs.read_gshhc(gshhs.fnames[resolution], poly=False, domain=domain): paths.extend(patch.geos_to_path(shapely.geometry.LineString(points))) # slinestring = shapely.geometry.LineString(points) # projected = projection.project_geometry(slinestring) # paths.extend(patch.geos_to_path(projected)) collection = PatchCollection([mpatches.PathPatch(pth) for pth in paths], edgecolor=outline_color, facecolor='none', transform=ccrs.PlateCarree(), **kwargs ) self.add_collection(collection, autolim=False)
def ll_boundary_poly_draw(self): for path in patch.geos_to_path(self.ll_boundary_poly()): # XXX Seems like great circle interpolation is making the plot strange... pp = mpatches.PathPatch(path, color='red', transform=cartopy.prj.PlateCarree(), alpha=0.5) dl = self.viewLim.get_points().copy() self.add_patch(pp) self.viewLim.set_points(dl)
def gshhs(self, outline_color='k', land_fill='green', ocean_fill='None', resolution='coarse', domain=None): import cartopy.gshhs as gshhs from matplotlib.collections import PatchCollection if ocean_fill is not None and land_fill is None: land_fill = self.outline_patch.get_facecolor() if domain is None: domain = self.ll_boundary_poly() paths = [] for points in gshhs.read_gshhc(gshhs.fnames[resolution], poly=True, domain=domain): # XXX Sometimes we only want to do lines... poly = shapely.geometry.Polygon(points[::-1, :]) projected = self.projection.project_polygon(poly) paths.extend(patch.geos_to_path(projected)) if ocean_fill is not None: self.outline_patch.set_facecolor(ocean_fill) collection = PatchCollection([mpatches.PathPatch(pth) for pth in paths], edgecolor=outline_color, facecolor=land_fill, zorder=2, ) # XXX Should it update the limits??? (AND HOW???) self.add_collection(collection)
def transform_path_non_affine(self, src_path): """ Transforms from source to target coordinates. Caches results, so subsequent calls with the same *src_path* argument (and the same source and target projections) are faster. Args: * src_path - A matplotlib :class:`~matplotlib.path.Path` object with vertices in source coordinates. Returns * A matplotlib :class:`~matplotlib.path.Path` with vertices in target coordinates. """ mapping = _PATH_TRANSFORM_CACHE.get(src_path) if mapping is not None: key = (self.source_projection, self.target_projection) result = mapping.get(key) if result is not None: return result bypass = self.source_projection == self.target_projection if bypass: projection = self.source_projection if isinstance(projection, ccrs._CylindricalProjection): x = src_path.vertices[:, 0] x_limits = projection.x_limits bypass = x.min() >= x_limits[0] and x.max() <= x_limits[1] if bypass: return src_path if src_path.vertices.shape == (1, 2): return mpath.Path(self.transform(src_path.vertices)) transformed_geoms = [] for geom in patch.path_to_geos(src_path): transformed_geoms.append(self.target_projection.project_geometry(geom, self.source_projection)) if not transformed_geoms: result = mpath.Path(numpy.empty([0, 2])) else: paths = patch.geos_to_path(transformed_geoms) if not paths: return mpath.Path(numpy.empty([0, 2])) points, codes = zip(*[patch.path_segments(path, curves=False, simplify=False) for path in paths]) result = mpath.Path(numpy.concatenate(points, 0), numpy.concatenate(codes)) # store the result in the cache for future performance boosts key = (self.source_projection, self.target_projection) if mapping is None: _PATH_TRANSFORM_CACHE[src_path] = {key: result} else: mapping[key] = result return result
def mpl_axes_plot(axes, geometries, **kwargs): """Plot lines on the given axes, given the geometries.""" # TODO: This interface should be exposed nicely on the geoaxes itself. import matplotlib.collections as mcollections import cartopy.mpl_integration.patch as patch paths = [] for geom in geometries: paths.extend(patch.geos_to_path(axes.projection.project_geometry(geom))) axes.add_collection(mcollections.PathCollection(paths, facecolor='none', **kwargs), autolim=False)
def draw_polygon(projection, polygon, color=None): multi_polygon = projection.project_geometry(polygon) for polygon in multi_polygon: #plt.plot(*zip(*polygon.exterior.coords), marker='+', color=color) #_arrows(projection, polygon.exterior) #continue import cartopy.mpl_integration.patch as patch paths = patch.geos_to_path(polygon) for pth in paths: patch = mpatches.PathPatch(pth, edgecolor='none', alpha=0.5, facecolor=color, lw=0) plt.gca().add_patch(patch)
def coastlines_land(self, facecolor=colors['land'], **kwargs): import cartopy.io.shapereader as shapereader land_path = shapereader.natural_earth(resolution='110m', category='physical', name='land') paths = [] for geom in shapereader.Reader(land_path).geometries(): paths.extend(patch.geos_to_path(self.projection.project_geometry(geom))) self.add_collection(mcollections.PathCollection(paths, facecolor=facecolor, **kwargs), autolim=False)
def show(projection, geometry): if geometry.type == 'MultiPolygon' and 1: multi_polygon = geometry for polygon in multi_polygon: import cartopy.mpl_integration.patch as patch paths = patch.geos_to_path(polygon) for pth in paths: patch = mpatches.PathPatch(pth, edgecolor='none', lw=0, alpha=0.2) plt.gca().add_patch(patch) line_string = polygon.exterior plt.plot(*zip(*line_string.coords), marker='+', linestyle='-') elif geometry.type == 'MultiPolygon': multi_polygon = geometry for polygon in multi_polygon: line_string = polygon.exterior plt.plot(*zip(*line_string.coords), marker='+', linestyle='-') elif geometry.type == 'MultiLineString': multi_line_string = geometry for line_string in multi_line_string: plt.plot(*zip(*line_string.coords), marker='+', linestyle='-') if 1: # Whole map domain plt.autoscale() elif 0: # The left-hand triangle plt.xlim(-1.65e7, -1.2e7) plt.ylim(0.3e7, 0.65e7) elif 0: # The tip of the left-hand triangle plt.xlim(-1.65e7, -1.55e7) plt.ylim(0.3e7, 0.4e7) elif 1: # The very tip of the left-hand triangle plt.xlim(-1.632e7, -1.622e7) plt.ylim(0.327e7, 0.337e7) elif 1: # The tip of the right-hand triangle plt.xlim(1.55e7, 1.65e7) plt.ylim(0.3e7, 0.4e7) plt.plot(*zip(*projection.boundary.coords), marker='o', scalex=False, scaley=False, zorder=-1) plt.show()
def transform_path_non_affine(self, path): if path.vertices.shape == (1, 2): return mpath.Path(self.transform(path.vertices)) transformed_geoms = [] for geom in patch.path_to_geos(path): transformed_geoms.append(self.target_projection.project_geometry(geom, self.source_projection)) if not transformed_geoms: return mpath.Path(numpy.empty([0, 2])) else: paths = patch.geos_to_path(transformed_geoms) if not paths: return mpath.Path(numpy.empty([0, 2])) points, codes = zip(*[patch.path_segments(path, curves=False, simplify=False) for path in paths]) return mpath.Path(numpy.concatenate(points, 0), numpy.concatenate(codes))
def _boundary(self): """ Adds the map's boundary. Note: The boundary is not the axes.patch, which provides rectilinear clipping for all of the map's artists. The axes.patch will have its visibility set to False inside GeoAxes.gca() """ import cartopy.mpl_integration.patch as p path, = p.geos_to_path(self.projection.boundary) # from matplotlib.collections import PatchCollection self.sct = sct = SimpleClippedTransform(self.transScale + self.transLimits, self.transAxes) # XXX Should be exactly one path... collection = mpatches.PathPatch(path, facecolor='none', edgecolor='k', zorder=1000, # transform=self.transData, transform=sct, clip_on=False, ) self.outline_patch = collection # XXX autolim = False self.add_patch(collection) # put a color patch for background color # XXX Should be exactly one path... collection = mpatches.PathPatch(path, facecolor='w', edgecolor='none', zorder= -1, transform=sct, clip_on=False, ) self.background_patch = collection # XXX autolim = False self.add_patch(collection) self.patch.set_facecolor((1, 1, 1, 0)) self.patch.set_edgecolor((0.5, 0.5, 0.5)) self.patch.set_linewidth(0.0)
def add_geometries(self, geoms, crs, **collection_kwargs): """ Add the given shapely geometries (in the given crs) to the axes as a :class:`~matplotlib.collections.PathCollection`. """ paths = [] key = (crs, self.projection) for geom in geoms: mapping = _GEOMETRY_TO_PATH_CACHE.setdefault(geom, {}) geom_paths = mapping.get(key) if geom_paths is None: projected = self.projection.project_geometry(geom, crs) geom_paths = patch.geos_to_path(projected) mapping[key] = geom_paths paths.extend(geom_paths) c = mcollections.PathCollection(paths, transform=self.projection, **collection_kwargs) self.add_collection(c, autolim=False) return c
def _boundary(self): """ Adds the map's boundary. Note, the boundary is not the axes.patch, which provides rectilinear clipping for all of the map's artists. The axes.patch will have its visibility set to False inside GeoAxes.gca() """ import cartopy.mpl_integration.patch as p path, = p.geos_to_path(self.projection.boundary) # from matplotlib.collections import PatchCollection self.sct = sct = SimpleClippedTransform(self.transScale + self.transLimits, self.transAxes) self.smt = SimpleMaskingTransform(self.transScale + self.transLimits, self.transAxes) # XXX Should be exactly one path... collection = mpatches.PathPatch(path, facecolor='none', edgecolor='k', zorder=1000, # transform=self.transData, transform=sct, clip_on=False, ) self.outline_patch = collection # XXX autolim = False self.add_patch(collection) # put a color patch for background color # XXX Should be exactly one path... collection = mpatches.PathPatch(path, facecolor='w', edgecolor='none', zorder= -1, transform=sct, clip_on=False, ) self.background_patch = collection # XXX autolim = False self.add_patch(collection) self.patch.set_facecolor((1, 1, 1, 0)) self.patch.set_edgecolor((0.5, 0.5, 0.5)) self.patch.set_linewidth(0.0)