Reputation: 1109
I want to use Shapely for my computational geometry project. I need to be able to visualize and display polygons, lines, and other geometric objects for this. I've tried to use Matplotlib for this but I am having trouble with it.
from shapely.geometry import Polygon
import matplotlib.pyplot as plt
polygon1 = Polygon([(0,5),
(1,1),
(3,0),
])
plt.plot(polygon1)
plt.show()
I would like to be able to display this polygon in a plot. How would I change my code to do this?
Upvotes: 103
Views: 162001
Reputation: 1365
It's possible to export geometries to SVG using the
shapely.geometry.base.BaseGeometry._repr_svg_
method. I would not use it for production-code, because it uses a 'protected member' of shapely.geometry.base class, but it works nicely for debugging.
Example:
drawing = MultiLineString([[[0, 0], [1, 2]], [[4, 4], [5, 6]]])
with open("geometry-dump.svg", 'w') as fh:
fh.write(drawing._repr_svg_())
Upvotes: 0
Reputation: 43622
If you are using Shapely 2.0+, use the shapely.plotting
module:
import shapely.plotting
from shapely.geometry import Polygon
polygon1 = Polygon([(0, 5), (1, 1), (3, 0)])
shapely.plotting.plot_polygon(polygon1)
Upvotes: 17
Reputation: 7494
Geometries can be Point
, LineString
, Polygon
, and their collection versions MultiPoint
, MultiLineString
, MultiPolygon
.
Point
Just pass the coordinates to pyplot
:
points = (point1, point2, point3, point3D)
xs = [point.x for point in points]
ys = [point.y for point in points]
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.scatter(xs, ys)
LineString
Just pass the x and y collections to pyplot
. They are obtained using xy
attribute. This attribute returns something like:
(array('d', [3.0, 2.0, 9.0]), array('d', [6.0, -1.0, 4.0]))
and can be used this way:
ax.plot(line.xy[0], line.xy[1])
ax.plot(*line.xy) # Equivalent
Polygon
For Polygon
, the currently accepted answer indeed works only for degraded polygons, that is polygons without holes. Here is a version working for any polygon with usual keywords for colors and other attributes. It's not my design, it's just adapted from GeoPandas source
import numpy as np
from matplotlib.path import Path
from matplotlib.patches import PathPatch
from matplotlib.collections import PatchCollection
# Plots a Polygon to pyplot `ax`
def plot_polygon(ax, poly, **kwargs):
path = Path.make_compound_path(
Path(np.asarray(poly.exterior.coords)[:, :2]),
*[Path(np.asarray(ring.coords)[:, :2]) for ring in poly.interiors])
patch = PathPatch(path, **kwargs)
collection = PatchCollection([patch], **kwargs)
ax.add_collection(collection, autolim=True)
ax.autoscale_view()
return collection
It is used this way:
from shapely.geometry import Polygon
import matplotlib.pyplot as plt
# Input polygon with two holes
# (remember exterior point order is ccw, holes cw else
# holes may not appear as holes.)
polygon = Polygon(shell=((0,0),(10,0),(10,10),(0,10)),
holes=(((1,3),(5,3),(5,1),(1,1)),
((9,9),(9,8),(8,8),(8,9))))
fig, ax = plt.subplots()
plot_polygon(ax, polygon, facecolor='lightblue', edgecolor='red')
Collections
For Multi
- collections, just call the plot function on each element.
Upvotes: 25
Reputation: 1365
You can also 'follow along' with the source code in the Shapely User Manual: (click on 'Source code).
The 'source code' provided here is not the actual Shapely source code, but the code used in the User Manual to create the examples. Using this 'example code' from the Shapely User Manual allows you to quickly create images in the same friendly style.
You'll need the 'figures' module, which is just one short, quite simple, python file from: https://github.com/Toblerity/Shapely/blob/main/docs/code/figures.py. (Taken from per https://gis.stackexchange.com/questions/362492/shapely-examples-use-figures-what-is-this-library)
Upvotes: 4
Reputation: 4745
Here is a solution using matplotlib patches that also accounts for holes:
import numpy as np
import shapely.geometry as sg
import matplotlib.pyplot as plt
import matplotlib.patches as patches
def add_polygon_patch(coords, ax, fc='blue'):
patch = patches.Polygon(np.array(coords.xy).T, fc=fc)
ax.add_patch(patch)
border = [(-10, -10), (-10, 10), (10, 10), (10, -10)] # Large square
holes = [
[(-6, -2), (-6, 2), (-2, 2), (-2, -2)], # Square hole
[(2, -2), (4, 2), (6, -2)] # Triangle hole
]
region = sg.Polygon(shell=border, holes=holes)
fig, ax = plt.subplots(1, 1)
add_polygon_patch(region.exterior, ax)
for interior in region.interiors:
add_polygon_patch(interior, ax, 'white')
ax.axis('equal')
plt.show()
Upvotes: 1
Reputation: 341
I was tired of Matplotlib's janky API for creating these plot images, so I made my own library. The Python module is called WKTPlot, and uses Bokeh to make interactive plots of your data. I have examples on how to plot WKT string data as well as data from Shapefiles.
It supports all most shapely geometric types:
Upvotes: 2
Reputation: 726
A little late but I find the most convenient way to do this is with Geopandas as suggested above but without writing to a file first.
from shapely.geometry import Polygon
import matplotlib.pyplot as plt
import geopandas as gpd
polygon1 = Polygon([(0,5),
(1,1),
(3,0),
])
p = gpd.GeoSeries(polygon1)
p.plot()
plt.show()
Checkout the docs for Geopandas.GeoSeries
Upvotes: 51
Reputation: 1551
If your data is in a .shp
file, I would recommend geopandas:
import geopandas as gpd
import matplotlib.pyplot as plt
shapefile = gpd.read_file("path/to/shapes.shp")
shapefile.plot()
plt.show()
Upvotes: 7
Reputation: 2614
Use:
import matplotlib.pyplot as plt
x,y = polygon1.exterior.xy
plt.plot(x,y)
Or, more succinctly:
plt.plot(*polygon1.exterior.xy)
Upvotes: 142
Reputation: 39
It might be an overkill, but as an alternative to other good comments I would add an option of installing QGIS - a free software for working with geometries. All you need to do is to save your geometries as a shape file (.shp), geoJSON or any other format and open it with QGIS. If you're planning a big project it maybe more convenient at the end than using matplotlib.
Upvotes: 3