# Plotting Voronoi diagram

I thought I’d post the code on how to plot voronoi diagrams using bokeh plots, since it has many use cases.

``````from scipy.spatial import Voronoi

def get_voronoi(coord_x, coord_y):
points = list(zip(coord_x, coord_y))
#Get Voronoi points
vor = Voronoi(points)

x_patch, y_patch = [], []
x1_patch, y1_patch = [], []
# The Voronoi has 2 parts. The actual patches and the unbounded lines (that run  #indefinitely)
for region in vor.regions:
if not -1 in region:
x1_patch, y1_patch = [], []
for i in region:
x1_patch.append(vor.vertices[i][0])
y1_patch.append(vor.vertices[i][1])

x_patch.append(np.array(x1_patch))
y_patch.append(np.array(y1_patch))

#This code that gets the multi lines that run indefinitely
center = vor.points.mean(axis=0)
ptp_bound = vor.points.ptp(axis=0)

line_segments = []
for pointidx, simplex in zip(vor.ridge_points, vor.ridge_vertices):
simplex = np.asarray(simplex)
if np.any(simplex < 0):
i = simplex[simplex >= 0][0]  # finite end Voronoi vertex

t = vor.points[pointidx[1]] - vor.points[pointidx[0]]  # tangent
t /= np.linalg.norm(t)
n = np.array([-t[1], t[0]])  # normal

midpoint = vor.points[pointidx].mean(axis=0)
direction = np.sign(np.dot(midpoint - center, n)) * n
far_point = vor.vertices[i] + direction * ptp_bound.max()

line_segments.append([(vor.vertices[i, 0], vor.vertices[i, 1]),
(far_point[0], far_point[1])])

x_vor_ls, y_vor_ls = [], []
for region in line_segments:

x1, y1 = [], []
for i in region:
x1.append(i[0])
y1.append(i[1])

x_vor_ls.append(np.array(x1))
y_vor_ls.append(np.array(y1))

#Removing patches that were added multiple times.
x_patch = list(OrderedDict((tuple(x), x) for x in x_patch).values())
y_patch = list(OrderedDict((tuple(x), x) for x in y_patch).values())
x_vor_ls = list(OrderedDict((tuple(x), x) for x in x_vor_ls).values())
y_vor_ls = list(OrderedDict((tuple(x), x) for x in y_vor_ls).values())

return x_patch, y_patch, x_vor_ls, y_vor_ls

x_patch, y_patch, x_vor_ls, y_vor_ls = get_voronoi(coord_x, coord_y)

source_vor = ColumnDataSource(dict(xs=x_patch, ys=y_patch))
source_vor_ls = ColumnDataSource(dict(xs=x_vor_ls, ys=y_vor_ls))

#plot patches for the Voronoi
glyph_vor = plot.patches('xs', 'ys', source=source_vor, alpha=0.3, line_width=1, fill_color='dodgerblue', line_color='black')

#plot the boundary lines
glyph_ls = plot.multi_line('xs', 'ys', source=source_vor_ls, alpha=1, line_width=1, line_color='black')

``````

(blue color are the patches and the lines that surround white areas are the multi lines.)

Hope it helps

4 Likes

This is great! Two things might be nice, if you are interested:

• Adding a `patches_from_voronoi` helper function to the library somehwere. (It could accept the output of `Voronoi` to avoid a dependency on Scipy)

• Adding an `voronoi.py` example shows off the above

1 Like

Shall I add them to `examples/reference/models/` ?

Would a `ipynb` be better than an `.py` for the complete example?

1 Like

Almost all the example in the main repo are small focused scripts, it’s just easier to manage. Something could also be added to the `bokeh-notebooks` repo potentially. But the main thing would be to define and add the convenience function, so that the example script itself could short, be only 10-20 lines long.

I.e., would like to avoid repeating the situation with `vector.py` where 90% of the example is supporting code to generate streamlines, unrelated to Bokeh. (In fact maybe that code would be moved to a convenience function too)

1 Like

I’ve added the function here patches_from_voronoi.py and the example code here voronoi.py

Thanks.

1 Like