【问题标题】:How do you select custom colours to fill regions of a Voronoi diagram using scipy.spatial's Voronoi package?如何使用 scipy.spatial 的 Voronoi 包选择自定义颜色来填充 Voronoi 图的区域?
【发布时间】:2020-08-10 20:28:44
【问题描述】:

我有一个读取 csv 文件的代码,该文件包含地点、纬度和经度以及我是否去过那里(标记为“Y”或“N”)。我想在 Voronoi 图中展示它,但最重要的是我想根据以下标准为区域着色:

  • 如果我没有去过那里 ('N') 将区域标记为白色
  • 如果我去过那里 ('Y') 将区域标记为地图上任何其他颜色所独有的随机颜色

我的代码有两个问题:我似乎无法将 Voronoi(coords) 生成的区域与我的原始地点列表相匹配(因此我无法轻易地将区域与我想要填充该区域的颜色对应起来,因为定义和填充区域的顺序不是它们在数据框中出现的顺序),其次,如何确保每个随机颜色是“唯一的”,即每个区域中出现的随机颜色不同。

我相当确定我可以找到解决方案的第二个问题,这是我正在努力解决的第一个问题。任何帮助将非常感激。这是我的代码:

import pandas as pd
from scipy.spatial import Voronoi, voronoi_plot_2d
import numpy as np

# read places, with lat and lon
places = pd.read_csv("places.csv")

# convert subset to numpy array
coords = places[['Longitude','Latitude']].values

# add 4 distant dummy points
coords = np.append(coords, [[999,999], [-999,999], [999,-999], [-999,-999]], axis = 0)
colours = np.append(places[['Been']].values, [['N'], ['N'], ['N'], ['N']], axis = 0).flatten()
colours = np.insert(colours, 0, ['N','N'])

# assign a random colour to the array if visited, leave white if not
colours[colours == 'N'] = 'w'
import random
r = lambda: random.randint(0,255)
colours[colours == 'Y'] = '#%02X%02X%02X' % (r(),r(),r())
print(places['Place'])
print(colours)
print(coords)
# compute voronoi tesselation
vor = Voronoi(coords)

# plot voronoi diagram
import matplotlib.pyplot as plt
fig = voronoi_plot_2d(vor, show_vertices = False)

j = -1
# colourise the regions
for region in vor.regions:
    j = j+1
    print(region)
    if not -1 in region:
        polygon = [vor.vertices[i] for i in region]
        plt.fill(*zip(*polygon), colours[j])

# fix the range of axes, plot locations
plt.plot(coords[:,0], coords[:,1], 'ko')
plt.xlim([places['Longitude'].min() - 0.6, places['Longitude'].max() + 0.6]), plt.ylim([places['Latitude'].min() - 0.6, places['Latitude'].max() + 0.6])

# annotate each point with the place name
[plt.annotate(places['Place'][i], (coords[i,0], coords[i,1]), xytext=(coords[i,0]-0.2, coords[i,1]+0.2)) for i in range(len(places))]
plt.show()

我在 Jupyter Notebooks 中制作了这个。我的 csv 文件如下所示:

Place,Latitude,Longitude,Been
Bern,46.948,7.4474,N
Juras,47.0086,6.7856,N
Lake Como,46.016,9.2572,N
Lyon,45.764,4.8357,N
Marseille,43.2965,5.3698,N
Milan,45.4642,9.19,N
Monaco,43.7384,7.4246,N
Mont Blanc,45.8326,6.8652,N
Mont Saleve,46.0942,6.1403,Y
Munich,48.1351,11.582,N
Turin,45.0703,7.6869,N
Zurich,47.3769,8.5417,N

如果有帮助的话,我已经留下了打印语句,以及我的测试中的一些注释代码行。我目前为里昂标记的区域着色,这表明我不知道如何使用region in vor.regions 来检索它对应的坐标的问题。提前致谢。

【问题讨论】:

    标签: python numpy random scipy voronoi


    【解决方案1】:

    您需要使用生成的 Voronoi 结果的 point_region 属性来确定哪个输入点对应于哪个 Voronoi 区域。这是为指示的区域着色的更新代码。

    我更新了代码,为每个有色 Voronoi 区域提供不同的随机颜色。代码如下:

    import pandas as pd
    from scipy.spatial import Voronoi, voronoi_plot_2d
    import numpy as np
    
    # read places, with lat and lon
    places = pd.read_csv("places.csv")
    
    # convert subset to numpy array
    coords = places[['Longitude','Latitude']].values
    
    # add 4 distant dummy points
    coords = np.append(coords, [[999,999], [-999,999], [999,-999], [-999,-999]], axis = 0)
    colourFlag = np.append(places[['Been']].values, [['N'], ['N'], ['N'], ['N']], axis = 0).flatten()
    
    # assign a random colour to the array if visited, leave white if not
    import random
    r = lambda: random.randint(0,255)
    colours = list(map(lambda flag: '#%02X%02X%02X' % (r(),r(),r()) if (flag == 'Y') else 'w', colourFlag))
    
    # compute voronoi tesselation
    vor = Voronoi(coords)
    
    # plot voronoi diagram
    import matplotlib.pyplot as plt
    fig = voronoi_plot_2d(vor, show_vertices = False)
    
    for j in range(len(coords)):
        region = vor.regions[vor.point_region[j]]
        if not -1 in region:
            polygon = [vor.vertices[i] for i in region]
            plt.fill(*zip(*polygon), colours[j])
    
    # fix the range of axes, plot locations
    plt.plot(coords[:,0], coords[:,1], 'ko')
    plt.xlim([places['Longitude'].min() - 0.6, places['Longitude'].max() + 0.6]), plt.ylim([places['Latitude'].min() - 0.6, places['Latitude'].max() + 0.6])
    
    # annotate each point with the place name
    [plt.annotate(places['Place'][i], (coords[i,0], coords[i,1]), xytext=(coords[i,0]-0.2, coords[i,1]+0.2)) for i in range(len(places))]
    plt.show()
    

    这是我为原始文件中的某些行添加颜色的绘图:

    【讨论】:

    • 啊,非常感谢,这正是我在寻找 Voronoi 的功能!我应该更多地查看文档,真的。也感谢您解决“随机”问题! (我不敢相信我离开了j = j+1 循环......当我发布这个问题时非常累,对不起!)
    猜你喜欢
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 1970-01-01
    • 2019-04-12
    • 1970-01-01
    相关资源
    最近更新 更多