How do I plot Shapely polygons and objects using Matplotlib?
Asked Answered
F

9

97

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?

Floribunda answered 4/4, 2019 at 18:4 Comment(3)
1. Nicely written first question! 2. If you can get individual lists of the x and y coordinates for your polygon you can plot like: plt.plot(polygon_x,polygon_y). You'll also have to append the first elements to the end to get the final line drawn. I unfortunately know nothing about shapely but hopefully this helps!Wryneck
It would be plt.plot(*polygon1.exterior.xy). More generally you can plot shapely objects through descates. Googling for "shapely matplotlib" should already give you relevant results.Hovel
geopandas.org may be worth investigating for this functionality.Croydon
C
135

Use:

import matplotlib.pyplot as plt

x,y = polygon1.exterior.xy
plt.plot(x,y)

Or, more succinctly:

plt.plot(*polygon1.exterior.xy)
Cristencristi answered 15/5, 2019 at 0:10 Comment(2)
this doesn't work for objects with holes in it unfortunatelyDihydrostreptomycin
If you want the interior rings (aka "holes") you can check from the LinearRings in polygon1.interiors.Ruby
L
48

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

Polygon Plotted using Geopandas

Checkout the docs for Geopandas.GeoSeries

Lipase answered 10/7, 2020 at 15:13 Comment(3)
The wrapping solution also helps to plot on a map: import mplleaflet; p.plot(); mplleaflet.show()Gladstone
@mins much like the accepted answer answers "how do I plot two numpy arrays for x and y", not "How do I plot Shapely polygons" ;)Th
Thanks, it works fine. If you want to plot multiple polygons on one plot, you can use ax = plt.axes(); poly1.plot(ax=ax); poly2.plot(ax=ax); plt.show().Brasca
R
24

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

enter image description here

Collections

For Multi- collections, just call the plot function on each element.

Rarefaction answered 30/12, 2021 at 14:35 Comment(0)
H
8

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)

enter image description here

Horsepower answered 12/4, 2023 at 22:3 Comment(3)
How would I save the plot to a file then?Heirship
fig, ax = plt.subplots() shapely.plotting.plot_polygon(polygon1, ax=ax) plt.savefig(f"{workspace}/test.png")Splatter
This is by far the easiestAshanti
B
7

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

Bolme answered 10/1, 2020 at 20:48 Comment(2)
Any way to plot this without writing to file first?Telephonist
You may be able to get away with wrapping the string in a StringIO as shown in this question, and passing the result to gpd.read_file though I have not tested this.Bolme
E
4

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.

Screenshot from https://shapely.readthedocs.io/en/latest/manual.html#linestrings november 2021

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)

Endopeptidase answered 29/11, 2021 at 10:49 Comment(0)
H
3

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.

Hydromagnetics answered 5/4, 2019 at 14:0 Comment(1)
Thank you. I am building a project that visualizes the Ham Sandwich theorem for my computational geometry course.Floribunda
M
2

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:

  • Point
  • MultiPoint
  • LineString
  • MultiLineString
  • LinearRing
  • Polygon
  • MultiPolygon
  • GeometryCollection
Milfordmilhaud answered 13/8, 2021 at 23:53 Comment(1)
It might be good to mention that one can pass the "Polgyon" object from the original question directly to this module. The examples on GitHub seem to suggest that you can only use (WKT) strings, but the add_shape method of the module also accepts many Shapely geometries.Endopeptidase
A
1

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

Polygon region with polygon holes from a

Aulos answered 9/11, 2021 at 19:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.