2

I want to draw Voronoi diagram in a square boundary. I tried to use voronoi_finite_polygons_2d() function. However, its result is not what I expected. The result is like below:

enter image description here

This picture is good, but I want to draw voronoi cells except for square's vertices([0,0], [1,0], [1,1], [0,1]) like this.

enter image description here

(I don't know this is correct diagram. However, I hope to say I want this kind of diagram.)

Because I want to get each cell's area in a finite boundary by using Polygon function.

import matplotlib.pyplot as plt
from shapely.geometry import MultiPoint, Point, Polygon
from scipy.spatial import Voronoi

def voronoi_finite_polygons_2d(vor, radius=None):
    """
    Reconstruct infinite voronoi regions in a 2D diagram to finite
    regions.
    Parameters
    ----------
    vor : Voronoi
        Input diagram
    radius : float, optional
        Distance to 'points at infinity'.
    Returns
    -------
    regions : list of tuples
        Indices of vertices in each revised Voronoi regions.
    vertices : list of tuples
        Coordinates for revised Voronoi vertices. Same as coordinates
        of input vertices, with 'points at infinity' appended to the
        end.
    """

    if vor.points.shape[1] != 2:
        raise ValueError("Requires 2D input")

    new_regions = []
    new_vertices = vor.vertices.tolist()

    center = vor.points.mean(axis=0)
    if radius is None:
        radius = vor.points.ptp().max()*2

    # Construct a map containing all ridges for a given point
    all_ridges = {}
    for (p1, p2), (v1, v2) in zip(vor.ridge_points, vor.ridge_vertices):
        all_ridges.setdefault(p1, []).append((p2, v1, v2))
        all_ridges.setdefault(p2, []).append((p1, v1, v2))

    # Reconstruct infinite regions
    for p1, region in enumerate(vor.point_region):
        vertices = vor.regions[region]

        if all(v >= 0 for v in vertices):
            # finite region
            new_regions.append(vertices)
            continue

        # reconstruct a non-finite region
        ridges = all_ridges[p1]
        new_region = [v for v in vertices if v >= 0]

        for p2, v1, v2 in ridges:
            if v2 < 0:
                v1, v2 = v2, v1
            if v1 >= 0:
                # finite ridge: already in the region
                continue

            # Compute the missing endpoint of an infinite ridge

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

            midpoint = vor.points[[p1, p2]].mean(axis=0)
            direction = np.sign(np.dot(midpoint - center, n)) * n
            far_point = vor.vertices[v2] + direction * radius

            new_region.append(len(new_vertices))
            new_vertices.append(far_point.tolist())

        # sort region counterclockwise
        vs = np.asarray([new_vertices[v] for v in new_region])
        c = vs.mean(axis=0)
        angles = np.arctan2(vs[:,1] - c[1], vs[:,0] - c[0])
        new_region = np.array(new_region)[np.argsort(angles)]

        # finish
        new_regions.append(new_region.tolist())

    return new_regions, np.asarray(new_vertices)

a = np.random.random(10)
b = np.random.random(10)
data = list(zip(a,b))
bound = [[0,0], [1,0], [1,1], [0,1]]

data.extend(bound)

points = np.array(data)

vor = Voronoi(points)
regions, vertices = voronoi_finite_polygons_2d(vor)

pts = MultiPoint([Point(i) for i in points])
mask = pts.convex_hull
new_vertices = []
for region in regions:
    polygon = vertices[region]
    shape = list(polygon.shape)
    shape[0] += 1
    p = Polygon(np.append(polygon, polygon[0]).reshape(*shape)).intersection(mask)
    poly = np.array(list(zip(p.boundary.coords.xy[0][:-1], p.boundary.coords.xy[1][:-1])))
    new_vertices.append(poly)
    plt.fill(*zip(*poly),"white", edgecolor = 'black', zorder = 1)

print(points)

plt.scatter(points[:,0], points[:,1], color = "blue", marker = "o", zorder = 2)
plt.xlim(0,1)
plt.ylim(0,1)
plt.show()
Gabriel
  • 40,504
  • 73
  • 230
  • 404
lksj
  • 49
  • 7
  • 1
    does this answer your question? https://stackoverflow.com/a/68117650/3896008 – lifezbeautiful Oct 02 '21 at 09:34
  • @lifezbeautiful thank you for your reply! Hmm.. yeah.. your link is similar to my expecting result, but not exactly same. First, I don't want to color the cells. Second, I cannot sure that the method can offer area value of cell to me – lksj Oct 14 '21 at 18:13
  • sorry missed this; yes of course, you get the areas a python dictionaries as in the `lat_lon_area` variable. The keys are your initial centres and the values are the computed areas; this git permalink should be self-explanatory; please let me know if that works; I can post an answer here but that would be almost a repitition of my answer over there, https://github.com/abcnishant007/mcvoronoi/blob/eebb40c3230eadb44d68bc0435199567c28d0a2f/source.py#L126 – lifezbeautiful Nov 07 '21 at 04:05

0 Answers0