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 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 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): 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))