2019-09-20 22:10:32 +00:00
|
|
|
"""Paths and patches"""
|
|
|
|
|
|
|
|
from matplotlib.patches import PathPatch
|
|
|
|
from matplotlib.path import Path
|
|
|
|
from numpy import asarray, concatenate, ones
|
|
|
|
|
|
|
|
|
|
|
|
class Polygon(object):
|
|
|
|
# Adapt Shapely or GeoJSON/geo_interface polygons to a common interface
|
|
|
|
def __init__(self, context):
|
|
|
|
if hasattr(context, 'interiors'):
|
|
|
|
self.context = context
|
|
|
|
else:
|
|
|
|
self.context = getattr(context, '__geo_interface__', context)
|
2019-10-17 12:29:52 +00:00
|
|
|
|
2019-09-20 22:10:32 +00:00
|
|
|
@property
|
|
|
|
def geom_type(self):
|
|
|
|
return (getattr(self.context, 'geom_type', None)
|
|
|
|
or self.context['type'])
|
2019-10-17 12:29:52 +00:00
|
|
|
|
2019-09-20 22:10:32 +00:00
|
|
|
@property
|
|
|
|
def exterior(self):
|
|
|
|
return (getattr(self.context, 'exterior', None)
|
|
|
|
or self.context['coordinates'][0])
|
2019-10-17 12:29:52 +00:00
|
|
|
|
2019-09-20 22:10:32 +00:00
|
|
|
@property
|
|
|
|
def interiors(self):
|
|
|
|
value = getattr(self.context, 'interiors', None)
|
|
|
|
if value is None:
|
|
|
|
value = self.context['coordinates'][1:]
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
def PolygonPath(polygon):
|
|
|
|
"""Constructs a compound matplotlib path from a Shapely or GeoJSON-like
|
|
|
|
geometric object"""
|
|
|
|
this = Polygon(polygon)
|
|
|
|
assert this.geom_type == 'Polygon'
|
|
|
|
def coding(ob):
|
|
|
|
# The codes will be all "LINETO" commands, except for "MOVETO"s at the
|
|
|
|
# beginning of each subpath
|
|
|
|
n = len(getattr(ob, 'coords', None) or ob)
|
|
|
|
vals = ones(n, dtype=Path.code_type) * Path.LINETO
|
|
|
|
vals[0] = Path.MOVETO
|
|
|
|
return vals
|
|
|
|
vertices = concatenate(
|
|
|
|
[asarray(this.exterior)]
|
|
|
|
+ [asarray(r) for r in this.interiors])
|
|
|
|
codes = concatenate(
|
|
|
|
[coding(this.exterior)]
|
|
|
|
+ [coding(r) for r in this.interiors])
|
|
|
|
return Path(vertices, codes)
|
|
|
|
|
|
|
|
|
|
|
|
def PolygonPatch(polygon, **kwargs):
|
|
|
|
"""Constructs a matplotlib patch from a geometric object
|
|
|
|
|
|
|
|
The `polygon` may be a Shapely or GeoJSON-like object with or without holes.
|
|
|
|
The `kwargs` are those supported by the matplotlib.patches.Polygon class
|
|
|
|
constructor. Returns an instance of matplotlib.patches.PathPatch.
|
|
|
|
|
|
|
|
Example (using Shapely Point and a matplotlib axes):
|
|
|
|
|
|
|
|
>>> b = Point(0, 0).buffer(1.0)
|
|
|
|
>>> patch = PolygonPatch(b, fc='blue', ec='blue', alpha=0.5)
|
|
|
|
>>> axis.add_patch(patch)
|
|
|
|
|
|
|
|
"""
|
|
|
|
return PathPatch(PolygonPath(polygon), **kwargs)
|