← Index fig. 9
Healthcare Access in Metro Atlanta
weighted Voronoi diagrams to measure Atlanta's health system imbalance
Public health clinics aren’t spread out evenly. Some sit in the middle of a dense ZIP code and get buried; others are on the edge of town and half-empty. I wanted a way to measure that imbalance, and then to ask where the clinics should be.
TLDR: a paper, “Dynamic Optimization of Health Facility Accessibility: A Voronoi Diagram Approach”. Every population point is assigned to its nearest facility with a Voronoi diagram, each facility gets a load score, and then a weighted k-means moves the facilities to even out the load. On 37 Atlanta ZIP codes and 10 public health facilities, the spread in population per facility dropped 44%, and the spread in load score dropped 55%. Later I turned it into a web app you can run on your own data.
The idea
A Voronoi diagram splits a map into cells, one per facility, where every point in a cell is closer to that facility than to any other. That’s a decent first guess at “who goes where”.
The companion notebook walks through a toy version first: a grid of random populations and five facilities, each cell coloured by how loaded it is.
Scoring a facility
Plain population per cell isn’t enough. Someone who lives far from their nearest clinic is worse off than someone next door to it, even if they’re in the same cell. So the score adds three things: the population in the cell, extra weight for people living farther than a radius r, and a fraction (ω) of the people just across the border in neighbouring cells, who might come over anyway.
Moving the clinics
Then I let the facilities move. Each iteration, every facility slides toward the population-weighted centre of its cell, with people beyond r weighted double and neighbours within c weighted by ω. Recompute the cells, repeat. It’s Lloyd’s algorithm with a public-health opinion baked into the weights.
Making it usable
The paper’s code was a script with hard-coded file paths. In 2026 I wrapped it in a small Flask app: upload facilities and population points (or use the Atlanta sample), set r, c and ω, and watch the regions update on a real map. There’s an iteration history so you can see it converge.
What I’d fix
The parameters committed in the repo have drifted from the paper (r is 0.05 there, 0.1 in the paper), and with those values the run doesn’t settle: from iteration 6 it flips between two layouts. Matching the paper’s values is the first fix. The bigger one is distance. I used straight-line distance on latitude and longitude, and nobody drives to a clinic in a straight line. Travel time would be the honest version.