SciPy Cheatsheet

Spatial

Use this SciPy reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Core Import

from scipy.spatial import (
    KDTree, cKDTree,
    Voronoi, ConvexHull, Delaunay, QhullError,
    distance_matrix,
    SphericalVoronoi,
    Rectangle
)
from scipy.spatial.distance import (
    cdist, pdist, squareform,
    euclidean, cityblock, cosine, correlation,
    minkowski, chebyshev, hamming, jaccard, dice, rogerstanimoto,
    directed_hausdorff
)
import numpy as np

Distance Computation

cdist — Cross-Set Distances

from scipy.spatial.distance import cdist

A = np.random.rand(50, 3)
B = np.random.rand(30, 3)

D = cdist(A, B, metric='euclidean')   # shape (50, 30)
D = cdist(A, B, metric='minkowski', p=3)
D = cdist(A, B, metric='cosine')
D = cdist(A, B, metric='correlation')
D = cdist(A, B, metric='cityblock')   # L1 / Manhattan
D = cdist(A, B, metric='chebyshev')   # L-inf
D = cdist(A, B, metric='hamming')     # for binary / integer vectors
D = cdist(A, B, metric='jaccard')     # set distance
D = cdist(A, B, metric='mahalanobis', VI=np.linalg.inv(np.cov(A.T)))

# Custom metric
D = cdist(A, B, metric=lambda u, v: np.sum(np.abs(u - v)**3)**(1/3))

pdist — Pairwise Distances Within a Set

from scipy.spatial.distance import pdist, squareform

A = np.random.rand(50, 3)

# Condensed form (upper triangle, length n*(n-1)/2)
d = pdist(A)                        # Euclidean
d = pdist(A, metric='cosine')
d = pdist(A, metric='minkowski', p=1.5)

# Convert to/from square matrix
D_sq = squareform(d)      # condensed → (n×n) square matrix
d_back = squareform(D_sq) # square → condensed

Metric Reference

MetricDescriptionData Type
'euclidean'L2 normcontinuous
'cityblock'L1 / Manhattancontinuous
'chebyshev'L-infcontinuous
'minkowski'L-p normcontinuous
'cosine'1 - cos(angle)continuous
'correlation'1 - Pearson rcontinuous
'mahalanobis'scaled by covariancecontinuous
'hamming'fraction of differing elementsbinary/int
'jaccard'set distancebinary
'dice'dice coefficientbinary
'rogerstanimoto'Rogers-Tanimotobinary
'canberra'weighted L1non-negative
'braycurtis'ecological distancenon-negative

Point-to-Point Utilities

from scipy.spatial.distance import euclidean, cityblock, cosine

euclidean([1, 0, 0], [0, 1, 0])   # sqrt(2)
cityblock([1, 2, 3], [4, 5, 6])   # 9
cosine([1, 0], [0, 1])            # 1.0 (orthogonal)

# Directed Hausdorff distance
from scipy.spatial.distance import directed_hausdorff

u = np.array([[0, 0], [1, 0], [1, 1]])
v = np.array([[0, 0], [0.5, 0.5]])
d, idx_u, idx_v = directed_hausdorff(u, v)

# Symmetric Hausdorff
haus = max(directed_hausdorff(u, v)[0], directed_hausdorff(v, u)[0])

Voronoi Diagrams

from scipy.spatial import Voronoi, voronoi_plot_2d

points = np.random.rand(20, 2)
vor = Voronoi(points)

vor.points           # input points
vor.vertices         # Voronoi vertices
vor.ridge_points     # pairs of input points for each ridge
vor.ridge_vertices   # Voronoi vertex indices for each ridge (-1 = at infinity)
vor.regions          # list of vertex index lists per region (-1 = unbounded)
vor.point_region     # region index for each input point

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
voronoi_plot_2d(vor, ax=ax, show_vertices=True, line_colors='black')

# Incremental (add points later)
vor = Voronoi(points, incremental=True)
vor.add_points(new_points)

Delaunay Triangulation

from scipy.spatial import Delaunay

points = np.random.rand(50, 2)
tri = Delaunay(points)

tri.simplices         # (nsimplex, ndim+1) array of vertex indices
tri.neighbors         # for each simplex: neighbor simplex indices (-1 = boundary)
tri.points            # input points
tri.convex_hull       # indices of boundary simplices

# Point location (find which triangle a point is in)
query = np.array([[0.5, 0.5], [0.1, 0.9]])
simplices = tri.find_simplex(query)    # -1 if outside hull

# Barycentric coordinates
b = tri.transform[simplices, :2] @ (query - tri.transform[simplices, 2]).T
# (more useful via tri.transform directly)

# Coplanarity check
in_hull = simplices >= 0

# Incremental
tri = Delaunay(points, incremental=True)
tri.add_points(new_points)

# Convex hull (as by-product)
from scipy.spatial import ConvexHull
hull = ConvexHull(points)
hull_vertices = hull.vertices          # indices of hull vertices (sorted CCW in 2D)
hull_simplices = hull.simplices        # facets (edges in 2D, triangles in 3D)
hull.volume                            # area in 2D, volume in 3D
hull.area                              # perimeter in 2D, surface area in 3D
hull.equations                         # facet hyperplane equations [normal, offset]

ConvexHull

from scipy.spatial import ConvexHull

pts = np.random.rand(100, 3)  # 3-D points
hull = ConvexHull(pts)

hull.vertices   # indices of hull vertices
hull.simplices  # triangular facets (indices into pts)
hull.volume     # volume
hull.area       # surface area
hull.equations  # (nfacet, 4) — [A, b] s.t. A @ x + b <= 0 inside

# Point-in-hull test (Delaunay method)
tri = Delaunay(pts)
inside = tri.find_simplex(test_pts) >= 0

# Incremental hull
hull = ConvexHull(pts, incremental=True)
hull.add_points(new_pts)

from scipy.spatial import convex_hull_plot_2d
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
convex_hull_plot_2d(ConvexHull(pts[:, :2]), ax=ax)

Spherical Voronoi

from scipy.spatial import SphericalVoronoi

# Points on the unit sphere
n = 100
theta = np.random.uniform(0, np.pi, n)
phi = np.random.uniform(0, 2*np.pi, n)
pts = np.column_stack([np.sin(theta)*np.cos(phi),
                        np.sin(theta)*np.sin(phi),
                        np.cos(theta)])

sv = SphericalVoronoi(pts, radius=1.0, center=np.array([0, 0, 0]))
sv.sort_vertices_of_regions()     # sort region vertices in CCW order

sv.vertices              # coordinates of Voronoi vertices on sphere
sv.regions               # list of vertex indices per region
sv.calculate_areas()     # area of each Voronoi cell (sum ≈ 4π)

Distance Matrix

from scipy.spatial import distance_matrix

A = np.random.rand(10, 3)
B = np.random.rand(8, 3)

D = distance_matrix(A, B)    # shape (10, 8), L2 by default
D = distance_matrix(A, B, p=1)   # L1 norm
D = distance_matrix(A, B, p=np.inf)   # Chebyshev

Common Gotchas

KDTree vs cKDTree: From SciPy 1.7+, KDTree is reimplemented in C++ and matches cKDTree performance. New code should use KDTree for cleaner import. Both share the same API.

query with distance_upper_bound: When a neighbor is not found within the bound, the returned index is tree.n (one past the last point) and distance is inf. Always filter with dist < np.inf before using indices.

query_ball_point returns unsorted results by default. Use return_sorted=True if you need consistent ordering, especially for reproducibility.

pdist condensed form vs square: pdist returns the upper triangle flattened. squareform(d)[i, j] gives the distance between points i and j. Passing a square matrix to squareform returns the condensed form.

Voronoi infinite regions: ridge_vertices entries of -1 indicate a ridge extending to infinity. voronoi_plot_2d clips these automatically, but manual processing requires checking for -1.

ConvexHull in high dimensions uses Qhull internally. For dimensions > ~10, performance degrades exponentially — consider approximate methods.