【问题标题】:Voronoi diagram in Manhattan metric曼哈顿度量中的 Voronoi 图
【发布时间】:2021-08-29 04:24:20
【问题描述】:

我正在使用 scipy.spatial 来可视化 Voronoi 图。但是,这里使用的距离度量是欧几里得 (L2)。我正在我的 Voronoi 图上寻找一种曼哈顿 (L1) 度量的方式。有没有简单(或多或少)的方法?

import numpy as np
import matplotlib.pyplot as plt

points = np.array([[1.5, 1.], [3.5, 1.], [5., 2.], [2.5, 3.], [3.5, 1.], [4., 4.]])
    
from scipy.spatial import Voronoi, voronoi_plot_2d
vor = Voronoi(points)

fig = plt.figure()
ax = fig.add_subplot('111')
ax.plot(points[:, 0], points[:, 1], 'o', color='k')
ax.set_xlim([-1, 9])
ax.set_ylim([-1, 9])
voronoi_plot_2d(vor, ax)

基本上我想得到类似的东西,但在 L1 指标中。

我找到了scipy.spatial.distance.cityblock 可以处理感兴趣的指标,但不完全确定如何实现它以使其正常工作?

【问题讨论】:

  • Manhattan Voronoi 有这个 python 实现:github.com/bobbysoon/TaxiVoronoi。我没有检查它是否/如何工作,但也许它会对你有所帮助。 (我通过这个 SO 答案找到了它:stackoverflow.com/a/31623208
  • 是的,我无法让它工作。
  • @bajun65537 想知道下面的解决方案是否适合您?

标签: python scipy voronoi


【解决方案1】:

我创建了一个 github 存储库,其中包含一个名为 voronoiz 的 Python 包,其中包括函数 voronoi_l1(用于计算 L1 Voronoi 图的多边形)和 voronoi_grid(用于计算任意距离的 Voronoi 图的图像) scipy.spatial.cdist 支持的指标)。

这些实现使用蛮力,O(n²) 算法,因此如果您将它用于数百万个点,它可能无法正常工作,但对于少量到中等数量的点,您可以使用它来制作好地块。

例如,这些由 10 个点组成的 Voronoi 图动画,其中一个点在圆周上移动,是由 voronoi_gridwrite_apng 组合而成的,来自 numpngw 库:

L1 指标:

Minkowksi 度量,p=2(即标准欧几里得度量):

Minkowski 度量,p=4:

这是生成动画的脚本:

import numpy as np
from voronoiz import voronoi_grid
from numpngw import write_apng


xmin = 0
xmax = 5
ymin = 0
ymax = 5

points = np.array([[0.00, 0.00],
                   [1.00, 4.51],
                   [1.20, 0.30],
                   [2.50, 2.60],
                   [2.40, 0.80],
                   [4.40, 3.30],
                   [1.95, 3.00],
                   [3.71, 1.90],
                   [4.50, 3.66],
                   [4.67, 0.21]])

gridsize = 299

for kwargs in [dict(metric='cityblock'),
               dict(metric='minkowski', p=2),
               dict(metric='minkowski', p=4)]:
    imgs = []
    for theta in np.linspace(0, 2*np.pi, 250, endpoint=False):
        # points[0] will travel about a circle.
        points[0] = 2.5 + 1.5*np.array([np.cos(theta), np.sin(theta)])
        img = voronoi_grid(points, xmin, xmax, ymin, ymax,
                           gridsize=(gridsize, gridsize),
                           **kwargs)
        img = (160//(len(points)+1)*img + 64).astype(np.uint8)
        img[img == 64] = 0
        for x, y in points:
            i = int(gridsize*(x - xmin)/(xmax - xmin))
            j = int(gridsize*(y - ymin)/(ymax - ymin))
            img[j-1:j+2, i-1:i+2] = 255
        img = np.pad(img, pad_width=1, mode='constant', constant_values=255)
        imgs.append(img)

    tag = '_'.join(f"{key}_{value}" for key, value in kwargs.items())
    write_apng(f'animation_{tag}.png', imgs, delay=100)

【讨论】:

  • 甜蜜!我相信它有效。
【解决方案2】:

如果区域的可视化和计算是您唯一的要求,您可以使用这个名为 mcvoronoi 的 pip 库,我们不久前做过。这是基于蒙特卡罗抽样。我添加了一个选项来更改此答案的距离度量。更新版本(带有距离度量选项)尚未在 pip 上发布,但您可以使用 github master 分支。用法如下图:

  • 在当前目录中克隆repository
  • 运行python example.py

example.py 由以下基本行组成:

lat_lon_area, mean_percentage_error = voronoi_area(points,voronoi_plot_enabled=True, NUM_COLORS=5, metric='manhattan')

图片保存如下:

您当然可以通过增加采样点的数量来使它们变得超级脆。还会生成显示面积计算误差的误差图。

您可能想要使用更多颜色,但如果您有足够多的区域,通常略多于4 colors 就足够了。

【讨论】:

    猜你喜欢
    • 2017-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多