Voronoi diagrams divide a coordinate plane into cells around the nearest input point. In SciPy, they help Python spatial workflows turn sample locations into region, ridge, and vertex data before plotting boundaries or assigning nearest-area labels.
scipy.spatial.Voronoi sends the coordinate array to Qhull and returns arrays that reference the original points. The finite vertices in vor.vertices define bounded ridge endpoints, vor.ridge_points names the two input points separated by each ridge, and -1 inside vor.ridge_vertices marks a ridge that extends to infinity.
The nine-point grid below creates one bounded center cell and several infinite outer cells, so the printed fields are easy to check before using less regular data. Use voronoi_plot_2d() only for 2-D plotting; the Voronoi object itself can represent diagrams in higher dimensions.
import matplotlib matplotlib.use("Agg") import numpy as np from pathlib import Path from scipy.spatial import Voronoi, voronoi_plot_2d np.set_printoptions(precision=1, suppress=True) points = np.array( [ [0.0, 0.0], [0.0, 1.0], [0.0, 2.0], [1.0, 0.0], [1.0, 1.0], [1.0, 2.0], [2.0, 0.0], [2.0, 1.0], [2.0, 2.0], ] ) vor = Voronoi(points) center_point = 4 center_region_index = vor.point_region[center_point] center_region = vor.regions[center_region_index] finite_ridges = [ridge for ridge in vor.ridge_vertices if -1 not in ridge] print("input points:", len(points)) print("Voronoi vertices:") for vertex in vor.vertices: print(f" [{vertex[0]:.1f}, {vertex[1]:.1f}]") print("regions total:", len(vor.regions)) print("point 4 region index:", center_region_index) print("point 4 region vertices:", center_region) print("finite ridges:", len(finite_ridges)) print("first ridge pairs:") for point_pair, vertex_pair in zip(vor.ridge_points[:4], vor.ridge_vertices[:4]): print(f" points {point_pair.tolist()} -> vertices {vertex_pair}") fig = voronoi_plot_2d( vor, show_vertices=False, line_colors="tab:blue", line_width=2, point_size=35, ) ax = fig.axes[0] ax.set_aspect("equal", adjustable="box") ax.set_xlim(-0.5, 2.5) ax.set_ylim(-0.5, 2.5) ax.set_title("Voronoi diagram") fig.savefig("voronoi-demo.png", dpi=150, bbox_inches="tight") print("saved plot:", Path("voronoi-demo.png").name)
The point array uses one x, y coordinate pair per row. matplotlib.use(“Agg”) keeps plot saving usable in terminals and notebooks without requiring a display window.
$ python3 voronoi_demo.py input points: 9 Voronoi vertices: [0.5, 0.5] [0.5, 1.5] [1.5, 0.5] [1.5, 1.5] regions total: 10 point 4 region index: 7 point 4 region vertices: [0, 1, 3, 2] finite ridges: 4 first ridge pairs: points [0, 3] -> vertices [-1, 0] points [0, 1] -> vertices [-1, 0] points [2, 5] -> vertices [-1, 1] points [2, 1] -> vertices [-1, 1] saved plot: voronoi-demo.png
The center input point at index 4 maps to a bounded region because its region vertex list has no -1 values.
center_region_index = vor.point_region[4] center_region = vor.regions[center_region_index]
point_region maps each input point index to an entry in vor.regions. The region list contains indexes into vor.vertices, not coordinate pairs.
for point_pair, vertex_pair in zip(vor.ridge_points, vor.ridge_vertices): print(point_pair, vertex_pair)
ridge_points stores the two input point indexes separated by the ridge. ridge_vertices stores the Voronoi vertex indexes that draw that ridge, with -1 marking an infinite edge.
fig = voronoi_plot_2d(vor, show_vertices=False) fig.savefig("voronoi-demo.png", dpi=150, bbox_inches="tight")
voronoi_plot_2d() requires Matplotlib and plots only 2-D diagrams. Keep the Voronoi object fields for geometry checks and downstream calculations.
Duplicate, collinear, or nearly degenerate points can raise QhullError or hide some regions in the 2-D plot. Use an option such as QJ deliberately after checking why the geometry is degenerate.
$ rm voronoi_demo.py voronoi-demo.png