223 lines
6.2 KiB
Python
223 lines
6.2 KiB
Python
"""Plot single geometries using Matplotlib.
|
|
|
|
Note: this module is experimental, and mainly targeting (interactive)
|
|
exploration, debugging and illustration purposes.
|
|
|
|
"""
|
|
|
|
import numpy as np
|
|
|
|
import shapely
|
|
|
|
|
|
def _default_ax():
|
|
import matplotlib.pyplot as plt
|
|
|
|
ax = plt.gca()
|
|
ax.grid(True)
|
|
ax.set_aspect("equal")
|
|
return ax
|
|
|
|
|
|
def _path_from_polygon(polygon):
|
|
from matplotlib.path import Path
|
|
|
|
from shapely.ops import orient
|
|
|
|
if isinstance(polygon, shapely.MultiPolygon):
|
|
return Path.make_compound_path(
|
|
*[_path_from_polygon(poly) for poly in polygon.geoms]
|
|
)
|
|
else:
|
|
polygon = orient(polygon)
|
|
return Path.make_compound_path(
|
|
Path(np.asarray(polygon.exterior.coords)[:, :2]),
|
|
*[Path(np.asarray(ring.coords)[:, :2]) for ring in polygon.interiors],
|
|
)
|
|
|
|
|
|
def patch_from_polygon(polygon, **kwargs):
|
|
"""Get a Matplotlib patch from a (Multi)Polygon.
|
|
|
|
Note: this function is experimental, and mainly targeting (interactive)
|
|
exploration, debugging and illustration purposes.
|
|
|
|
Parameters
|
|
----------
|
|
polygon : shapely.Polygon or shapely.MultiPolygon
|
|
The polygon to convert to a Matplotlib Patch.
|
|
**kwargs
|
|
Additional keyword arguments passed to the matplotlib Patch.
|
|
|
|
Returns
|
|
-------
|
|
Matplotlib artist (PathPatch)
|
|
|
|
"""
|
|
from matplotlib.patches import PathPatch
|
|
|
|
return PathPatch(_path_from_polygon(polygon), **kwargs)
|
|
|
|
|
|
def plot_polygon(
|
|
polygon,
|
|
ax=None,
|
|
add_points=True,
|
|
color=None,
|
|
facecolor=None,
|
|
edgecolor=None,
|
|
linewidth=None,
|
|
**kwargs,
|
|
):
|
|
"""Plot a (Multi)Polygon.
|
|
|
|
Note: this function is experimental, and mainly targeting (interactive)
|
|
exploration, debugging and illustration purposes.
|
|
|
|
Parameters
|
|
----------
|
|
polygon : shapely.Polygon or shapely.MultiPolygon
|
|
The polygon to plot.
|
|
ax : matplotlib Axes, default None
|
|
The axes on which to draw the plot. If not specified, will get the
|
|
current active axes or create a new figure.
|
|
add_points : bool, default True
|
|
If True, also plot the coordinates (vertices) as points.
|
|
color : matplotlib color specification
|
|
Color for both the polygon fill (face) and boundary (edge). By default,
|
|
the fill is using an alpha of 0.3. You can specify `facecolor` and
|
|
`edgecolor` separately for greater control.
|
|
facecolor : matplotlib color specification
|
|
Color for the polygon fill.
|
|
edgecolor : matplotlib color specification
|
|
Color for the polygon boundary.
|
|
linewidth : float
|
|
The line width for the polygon boundary.
|
|
**kwargs
|
|
Additional keyword arguments passed to the matplotlib Patch.
|
|
|
|
Returns
|
|
-------
|
|
Matplotlib artist (PathPatch), if `add_points` is false.
|
|
A tuple of Matplotlib artists (PathPatch, Line2D), if `add_points` is true.
|
|
|
|
"""
|
|
from matplotlib import colors
|
|
|
|
if ax is None:
|
|
ax = _default_ax()
|
|
|
|
if color is None:
|
|
color = "C0"
|
|
color = colors.to_rgba(color)
|
|
|
|
if facecolor is None:
|
|
facecolor = list(color)
|
|
facecolor[-1] = 0.3
|
|
facecolor = tuple(facecolor)
|
|
|
|
if edgecolor is None:
|
|
edgecolor = color
|
|
|
|
patch = patch_from_polygon(
|
|
polygon, facecolor=facecolor, edgecolor=edgecolor, linewidth=linewidth, **kwargs
|
|
)
|
|
ax.add_patch(patch)
|
|
ax.autoscale_view()
|
|
|
|
if add_points:
|
|
line = plot_points(polygon, ax=ax, color=color)
|
|
return patch, line
|
|
|
|
return patch
|
|
|
|
|
|
def plot_line(line, ax=None, add_points=True, color=None, linewidth=2, **kwargs):
|
|
"""Plot a (Multi)LineString/LinearRing.
|
|
|
|
Note: this function is experimental, and mainly targeting (interactive)
|
|
exploration, debugging and illustration purposes.
|
|
|
|
Parameters
|
|
----------
|
|
line : shapely.LineString or shapely.LinearRing
|
|
The line to plot.
|
|
ax : matplotlib Axes, default None
|
|
The axes on which to draw the plot. If not specified, will get the
|
|
current active axes or create a new figure.
|
|
add_points : bool, default True
|
|
If True, also plot the coordinates (vertices) as points.
|
|
color : matplotlib color specification
|
|
Color for the line (edgecolor under the hood) and points.
|
|
linewidth : float, default 2
|
|
The line width for the polygon boundary.
|
|
**kwargs
|
|
Additional keyword arguments passed to the matplotlib Patch.
|
|
|
|
Returns
|
|
-------
|
|
Matplotlib artist (PathPatch)
|
|
|
|
"""
|
|
from matplotlib.patches import PathPatch
|
|
from matplotlib.path import Path
|
|
|
|
if ax is None:
|
|
ax = _default_ax()
|
|
|
|
if color is None:
|
|
color = "C0"
|
|
|
|
if isinstance(line, shapely.MultiLineString):
|
|
path = Path.make_compound_path(
|
|
*[Path(np.asarray(mline.coords)[:, :2]) for mline in line.geoms]
|
|
)
|
|
else:
|
|
path = Path(np.asarray(line.coords)[:, :2])
|
|
|
|
patch = PathPatch(
|
|
path, facecolor="none", edgecolor=color, linewidth=linewidth, **kwargs
|
|
)
|
|
ax.add_patch(patch)
|
|
ax.autoscale_view()
|
|
|
|
if add_points:
|
|
line = plot_points(line, ax=ax, color=color)
|
|
return patch, line
|
|
|
|
return patch
|
|
|
|
|
|
def plot_points(geom, ax=None, color=None, marker="o", **kwargs):
|
|
"""Plot a Point/MultiPoint or the vertices of any other geometry type.
|
|
|
|
Parameters
|
|
----------
|
|
geom : shapely.Geometry
|
|
Any shapely Geometry object, from which all vertices are extracted
|
|
and plotted.
|
|
ax : matplotlib Axes, default None
|
|
The axes on which to draw the plot. If not specified, will get the
|
|
current active axes or create a new figure.
|
|
color : matplotlib color specification
|
|
Color for the filled points. You can use `markeredgecolor` and
|
|
`markerfacecolor` to have different edge and fill colors.
|
|
marker : str, default "o"
|
|
The matplotlib marker for the points.
|
|
**kwargs
|
|
Additional keyword arguments passed to matplotlib `plot` (Line2D).
|
|
|
|
Returns
|
|
-------
|
|
Matplotlib artist (Line2D)
|
|
|
|
"""
|
|
if ax is None:
|
|
ax = _default_ax()
|
|
|
|
coords = shapely.get_coordinates(geom)
|
|
(line,) = ax.plot(
|
|
coords[:, 0], coords[:, 1], linestyle="", marker=marker, color=color, **kwargs
|
|
)
|
|
return line
|