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.
Steps to create a Voronoi diagram with SciPy:
- Create a Python script named voronoi_demo.py.
- voronoi_demo.py
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.
- Run the script to build the diagram and save the plot.
$ 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.
- Use point_region and regions to find the cell for one input point.
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.
- Use ridge_points and ridge_vertices to map ridge lines back to source points.
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.
- Save a 2-D plot with voronoi_plot_2d() when a visual diagram is needed.
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.
- Add qhull_options only when the input geometry needs it.
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.
- Remove the demo files when the check is complete.
$ rm voronoi_demo.py voronoi-demo.png
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.