def draw_vor(pos, partition): # stack coordinates of nodes in coor_lis to draw the Voronoi Diagram # indices of coor_lis correspond to the node coor_lis = [] for p in range(0, len(pos.keys())): coor_lis.append(pos[str(p)]) vor = Voronoi(np.stack(coor_lis)) # build dictionary to store community info # com_node = {community: [nodes in community]} com_node = {} for p, com in partition.items(): com_node.setdefault(com, []).append(p) # merge voronoi cells for each community # record attributes of vor needed to be modified regions_remove = [] point_region_remove = [] ridge_points_remove = [] ridge_vertices_remove = [] vor_ridge_points = vor.ridge_points.tolist() vor_point_region = vor.point_region.tolist() for p_lis in com_node.values(): regions_lis, point_region_lis, ridge_points_lis, ridge_vertices_lis\ = merge_vor(vor_ridge_points, vor.ridge_vertices, vor.regions, vor_point_region, p_lis) regions_remove += regions_lis point_region_remove += point_region_lis ridge_points_remove += ridge_points_lis ridge_vertices_remove += ridge_vertices_lis # modified attributes of vor # vor.point_region for r in point_region_remove: vor_point_region.remove(r) vor.point_region = np.array(vor_point_region) # vor.regions for i in regions_remove: vor.regions.remove(i) # vor.ridge_points for pair in ridge_points_remove: vor_ridge_points.remove(pair) vor.ridge_points = np.array(vor_ridge_points) # vor.ridge_vertices for pair in ridge_vertices_remove: try: vor.ridge_vertices.remove(pair) except: v1, v2 = pair vor.ridge_vertices.remove([v2, v1]) # plot Voronoi diagram voronoi_plot_2d(vor, show_vertices=False, line_width=0) plt.show()
def finite_voronoi(vor, scale=1): """ finite_voronoi(vor, scale=1) Construct finite boundaries for Voronoi diagram. Parameters ---------- points : ndarray of floats, shape (npoints, 2) Coordinates of points to construct a convex hull from scale : float, optional Scale of extension lines. Some points may be outside their associated region if scale < 1 Attributes ---------- points : ndarray of double, shape (npoints, 2) Coordinates of input points. vertices : ndarray of double, shape (nvertices, 2) Coordinates of the Voronoi vertices. ridge_points : ndarray of ints, shape (nridges, 2) Indices of the points between which each Voronoi ridge lies. ridge_vertices : list of list of ints, shape (nridges, *) Indices of the Voronoi vertices forming each Voronoi ridge. regions : list of list of ints, shape (nregions, *) Indices of the Voronoi vertices forming each Voronoi region. point_region : list of ints, shape (npoints) Index of the Voronoi region for each input point. """ vor = Voronoi(points) # Calculate size of extension lines ptp_bound = vor.points.ptp(axis=0).max() * scale # Count number of new vertices required nv_existing = len(vor.vertices) nv_required = len([v for v in vor.ridge_vertices if v[0] < 0]) new_vertices = list(range(nv_existing, nv_existing + nv_required)) outer_vertices = [] center = vor.points.mean(axis=0) for idx, pointidx, simplex in zip(range(len(vor.ridge_points)), vor.ridge_points, vor.ridge_vertices): simplex = np.asarray(simplex) if np.any(simplex < 0): # Find finite end Voronoi vertex i = simplex[simplex >= 0][0] # Calculate tangent and normal t = vor.points[pointidx[1]] - vor.points[pointidx[0]] t /= np.linalg.norm(t) n = np.array([-t[1], t[0]]) # Draw line midpoint = vor.points[pointidx].mean(axis=0) direction = np.sign(np.dot(midpoint - center, n)) * n far_point = vor.vertices[i] + direction * ptp_bound outer_vertices.append(list(pointidx)) # Add start point to ridge vertices vor.ridge_vertices[idx][0] = len(vor.vertices) vor.vertices = np.vstack([vor.vertices, far_point]) # Assign points to outer vertices outer_points = list( set([item for sublist in outer_vertices for item in sublist])) for op in outer_points: p = [nv for nv, ov in zip(new_vertices, outer_vertices) if op in ov] vor.ridge_vertices = np.vstack([vor.ridge_vertices, p]) vor.ridge_points = np.vstack([vor.ridge_points, [op, -1]]) # Cycle through points for point_idx in range(len(vor.points)): region_idx = vor.point_region[point_idx] segs = vor.ridge_vertices[(vor.ridge_points == point_idx).any(axis=1)] # Remove first point from segment, to force correct direction segs[0, 0] = segs[0, 1] # Put segments in correct order for i in range(1, len(segs)): idx = np.where([np.any(np.in1d(segs[i - 1], s)) for s in segs[i:]])[0][-1] segs[i:] = np.roll(segs[i:], -idx, axis=0) # Extract vertices from segments pts = segs.flatten() _, i = np.unique(pts, return_index=True) vor.regions[region_idx] = pts[np.sort(i)] return vor