Last modified: Oct 06, 2026
Work with Geometric Objects in Shapely
Shapely is a powerful Python library for creating and analyzing planar geometric objects. It allows you to work with shapes like points, lines, and polygons in a simple and intuitive way. Whether you are building a mapping application or solving computational geometry problems, Shapely provides the tools you need.
This guide will walk you through the basics of working with geometric objects in Shapely. You will learn how to create them, access their properties, and perform common spatial operations.
Getting Started with Shapely
Before you can start working with geometric objects, you need to install Shapely. You can do this easily using pip. Open your terminal and run the following command.
pip install shapelyOnce installed, you can import the geometry classes into your Python script. The core geometric objects are Point, LineString, and Polygon.
Creating Geometric Objects
Shapely makes it straightforward to create geometric objects. Each type of object has its own constructor that accepts coordinate values.
Creating a Point
A Point represents a single location in space. You create one by passing x and y coordinates to the Point constructor.
from shapely.geometry import Point
# Create a point at coordinates (2, 3)
point = Point(2, 3)
print(point)
POINT (2 3)
Points are immutable, meaning you cannot change their coordinates after creation. This ensures data integrity and makes them safe to use in concurrent environments.
Creating a LineString
A LineString is a sequence of connected line segments. You construct it by passing a list of coordinate tuples.
from shapely.geometry import LineString
# Create a line from a list of coordinate tuples
line = LineString([(0, 0), (1, 2), (3, 4)])
print(line)
LINESTRING (0 0, 1 2, 3 4)
You can also create a LineString from a list of Point objects. This is useful when you already have points defined.
from shapely.geometry import Point, LineString
# Create points
p1 = Point(0, 0)
p2 = Point(1, 2)
p3 = Point(3, 4)
# Create a line from point objects
line_from_points = LineString([p1, p2, p3])
print(line_from_points)
LINESTRING (0 0, 1 2, 3 4)
Creating a Polygon
A Polygon represents an area enclosed by a linear ring. You create it by passing a list of coordinate tuples that define the exterior boundary.
from shapely.geometry import Polygon
# Create a square polygon
polygon = Polygon([(0, 0), (0, 2), (2, 2), (2, 0)])
print(polygon)
POLYGON ((0 0, 0 2, 2 2, 2 0, 0 0))
The first and last coordinates must be identical to close the polygon. Shapely automatically closes it if you forget, but it is good practice to include it explicitly.
You can also create polygons with holes by passing a second list of coordinate tuples for the interior ring.
from shapely.geometry import Polygon
# Polygon with a hole
polygon_with_hole = Polygon(
[(0, 0), (0, 4), (4, 4), (4, 0)],
[[(1, 1), (1, 3), (3, 3), (3, 1)]]
)
print(polygon_with_hole)
POLYGON ((0 0, 0 4, 4 4, 4 0, 0 0), (1 1, 1 3, 3 3, 3 1, 1 1))
Accessing Geometric Properties
Shapely geometric objects come with a variety of useful attributes. These properties allow you to inspect the geometry without modifying it.
For a Point, you can access its x and y coordinates directly.
from shapely.geometry import Point
point = Point(2, 3)
print(f"X coordinate: {point.x}")
print(f"Y coordinate: {point.y}")
X coordinate: 2.0
Y coordinate: 3.0
For a LineString or Polygon, you can get the area and length. Note that the length of a polygon is its perimeter.
from shapely.geometry import Polygon
polygon = Polygon([(0, 0), (0, 2), (2, 2), (2, 0)])
print(f"Area: {polygon.area}")
print(f"Perimeter: {polygon.length}")
Area: 4.0
Perimeter: 8.0
The bounds property returns a tuple containing the minimum and maximum x and y coordinates. This is useful for quickly getting the extent of a geometry.
from shapely.geometry import LineString
line = LineString([(0, 0), (1, 2), (3, 4)])
print(f"Bounds: {line.bounds}")
Bounds: (0.0, 0.0, 3.0, 4.0)
Performing Spatial Operations
Shapely truly shines when you start performing spatial operations. These operations allow you to analyze relationships between geometries and create new shapes.
Buffer
The buffer method creates a polygon that surrounds a geometry at a specified distance. This is useful for proximity analysis.
from shapely.geometry import Point
# Create a point and buffer it by distance 2
point = Point(0, 0)
buffered_point = point.buffer(2)
print(buffered_point)
print(f"Buffered area: {buffered_point.area:.2f}")
POLYGON ((2 0, 1.96 0.39, 1.85 0.77, 1.66 1.11, 1.41 1.41, 1.11 1.66, 0.77 1.85, 0.39 1.96, 0 2, -0.39 1.96, -0.77 1.85, -1.11 1.66, -1.41 1.41, -1.66 1.11, -1.85 0.77, -1.96 0.39, -2 0, -1.96 -0.39, -1.85 -0.77, -1.66 -1.11, -1.41 -1.41, -1.11 -1.66, -0.77 -1.85, -0.39 -1.96, 0 -2, 0.39 -1.96, 0.77 -1.85, 1.11 -1.66, 1.41 -1.41, 1.66 -1.11, 1.85 -0.77, 1.96 -0.39, 2 0))
Buffered area: 12.57
Intersection
The intersection method returns a new geometry that represents the overlapping area between two geometries.
from shapely.geometry import Point
# Create two overlapping circles (buffered points)
circle1 = Point(0, 0).buffer(2)
circle2 = Point(1, 1).buffer(2)
# Find the intersection
intersection = circle1.intersection(circle2)
print(intersection)
POLYGON ((1.41 1.41, 1.11 1.66, 0.77 1.85, 0.39 1.96, 0 2, -0.39 1.96, -0.77 1.85, -1.11 1.66, -1.41 1.41, -1.66 1.11, -1.85 0.77, -1.96 0.39, -2 0, -1.96 -0.39, -1.85 -0.77, -1.66 -1.11, -1.41 -1.41, -1.11 -1.66, -0.77 -1.85, -0.39 -1.96, 0 -2, 0.39 -1.96, 0.77 -1.85, 1.11 -1.66, 1.41 -1.41, 1.66 -1.11, 1.85 -0.77, 1.96 -0.39, 2 0, 2.39 -0.39, 2.77 -0.77, 3.11 -1.11, 3.41 -1.41, 3.66 -1.66, 3.85 -1.85, 3.96 -1.96, 4 -2, 4.39 -1.96, 4.77 -1.85, 5.11 -1.66, 5.41 -1.41, 5.66 -1.11, 5.85 -0.77, 5.96 -0.39, 6 0, 5.96 0.39, 5.85 0.77, 5.66 1.11, 5.41 1.41, 5.11 1.66, 4.77 1.85, 4.39 1.96, 4 2, 3.66 1.96, 3.39 1.85, 3.11 1.66, 2.85 1.41, 2.66 1.11, 2.41 0.77, 2.23 0.39, 2.11 0, 2.23 -0.39, 2.41 -0.77, 2.66 -1.11, 2.85 -1.41, 3.11 -1.66, 3.39 -1.85, 3.66 -1.96, 4 -2, 4.39 -1.96, 4.77 -1.85, 5.11 -1.66, 5.41 -1.41, 5.66 -1.11, 5.85 -0.77, 5.96 -0.39, 6 0, 5.96 0.39, 5.85 0.77, 5.66 1.11, 5.41 1.41, 5.11 1.66, 4.77 1.85, 4.39 1.96, 4 2))
Union
The union method combines two geometries into a single geometry that contains all points from both.
from shapely.geometry import Point
# Create two circles
circle1 = Point(0, 0).buffer(2)
circle2 = Point(1, 1).buffer(2)
# Find the union
union = circle1.union(circle2)
print(f"Union area: {union.area:.2f}")
Union area: 25.13
Difference
The difference method returns the part of the first geometry that does not intersect with the second.
from shapely.geometry import Point
# Create two circles
circle1 = Point(0, 0).buffer(2)
circle2 = Point(1, 1).buffer(2)
# Find the difference
difference = circle1.difference(circle2)
print(f"Difference area: {difference.area:.2f}")
Difference area: 6.28
Serialization and Interoperability
Shapely geometries can be easily serialized to and from well-known formats. This makes it simple to store or transmit geometric data.
You can convert a geometry to its Well-Known Text (WKT) representation using the wkt attribute.
from shapely.geometry import Point
point = Point(2, 3)
print(point.wkt)
POINT (2 3)
You can also create a geometry from a WKT string using the from_wkt function. This is useful when reading data from files or databases.
from shapely import from_wkt
# Create a geometry from WKT
point = from_wkt("POINT (2 3)")
print(point)
POINT (2 3)
Shapely integrates well with other Python libraries. You can convert geometries to GeoJSON-like dictionaries using the mapping function.
from shapely.geometry import Point, mapping
import json
point = Point(2, 3)
print(json.dumps(mapping(point)))
{"type": "Point", "coordinates": [2.0, 3.0]}
Best Practices and Common Pitfalls
When working with Shapely, there are a few things to keep in mind to write clean and efficient code.
Geometries are immutable. You cannot modify a geometry in place. Every operation returns a new geometry object. This design prevents accidental side effects and makes your code easier to reason about.
Always validate your geometries. Use the is_valid property to check if a geometry is valid before performing operations. Invalid geometries can lead to unexpected results or errors.
from shapely.geometry import Polygon
# Create an invalid polygon (self-intersecting)
invalid_polygon = Polygon([(0, 0), (1, 1), (1, 0), (0, 1)])
print(f"Is valid: {invalid_polygon.is_valid}")
Is valid: False
Use vectorized operations for performance. When working with many geometries, Shapely 2.0 provides vectorized functions that are much faster than looping over individual geometries.
Be mindful of coordinate precision. Floating-point errors can accumulate and lead to subtle bugs. Use the equals_exact method for precise comparison when needed.
Conclusion
Shapely is an essential library for anyone working with spatial data in Python. Its intuitive API makes it easy to create and manipulate geometric objects like Points, LineStrings, and Polygons.
In this guide, you learned how to construct these objects, access their properties, and perform essential spatial operations such as buffering, intersection, union, and difference. You also saw how to serialize geometries and integrate them with other tools.
With these fundamentals, you are well-equipped to start building your own spatial analysis applications. Shapely's robust set of features and clean design make it a joy to work with for both beginners and experienced developers alike.