You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Scipy生成Voronoi图出现异常结果的问题排查

Voronoi图边界缺失/异常的解决思路

问题背景

使用Scipy的Voronoi工具生成图时,出现边界缺失、显示异常的问题,原始数据和代码如下:

原始DataFrame

import pandas as pd
centers_dt = pd.DataFrame({
    'cl': {0: 'A', 1: 'C', 2: 'H', 3: 'M', 4: 'S'},
    'd': {0: 245.059986986012,
          1: 320.49044143557785,
          2: 239.79023081978914,
          3: 263.38325791238833,
          4: 219.53334398353175},
    'p': {0: 10.971011721360075,
          1: 10.970258360366753,
          2: 13.108487516946218,
          3: 12.93241352743668,
          4: 13.346107628161008}
})

原始绘图代码

import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Voronoi, voronoi_plot_2d

centers2 = np.array(centers_dt[['d', 'p']])

scatter_x = np.array(centers_dt['d'])
scatter_y = np.array(centers_dt['p'])
group = np.array(centers_dt['cl'])
cdict = {'C': 'red', 'A': 'blue', 'H': 'green', 'M': 'yellow', 'S': 'black'}

fig, ax = plt.subplots()
for g in np.unique(group):
    ix = np.where(group == g)
    ax.scatter(scatter_x[ix], scatter_y[ix], c = cdict[g], label = g, s = 100)
ax.legend()

vor = Voronoi(centers2)
fig = voronoi_plot_2d(vor,plt.gca())

plt.show()
plt.close()

核心原因

Scipy的Voronoi默认不会处理无限远顶点(即位于数据集边界之外的Voronoi区域顶点),导致这些区域的边界无法正常绘制;同时绘图时坐标轴范围未适配,会进一步裁剪掉部分边界。

解决步骤

1. 补充无限远顶点的边界坐标

手动计算数据的极值范围,将无限远顶点替换为落在坐标轴边界上的点,确保所有Voronoi区域都有闭合边界。

2. 统一坐标轴范围

设置坐标轴的上下限,覆盖所有数据点和补充的边界点,避免图形被裁剪。

3. 优化绘图逻辑

确保Voronoi图和散点图在同一轴上绘制,避免图层冲突。

修改后的完整代码

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

# 原始数据
centers_dt = pd.DataFrame({
    'cl': {0: 'A', 1: 'C', 2: 'H', 3: 'M', 4: 'S'},
    'd': {0: 245.059986986012,
          1: 320.49044143557785,
          2: 239.79023081978914,
          3: 263.38325791238833,
          4: 219.53334398353175},
    'p': {0: 10.971011721360075,
          1: 10.970258360366753,
          2: 13.108487516946218,
          3: 12.93241352743668,
          4: 13.346107628161008}
})

centers2 = np.array(centers_dt[['d', 'p']])
scatter_x = centers_dt['d'].values
scatter_y = centers_dt['p'].values
group = centers_dt['cl'].values
cdict = {'C': 'red', 'A': 'blue', 'H': 'green', 'M': 'yellow', 'S': 'black'}

# 计算数据边界,留10%的余量
x_min, x_max = scatter_x.min() * 0.9, scatter_x.max() * 1.1
y_min, y_max = scatter_y.min() * 0.9, scatter_y.max() * 1.1

vor = Voronoi(centers2)

# 初始化绘图,先绘制基础Voronoi线条(隐藏顶点)
fig, ax = plt.subplots()
voronoi_plot_2d(vor, ax=ax, show_vertices=False, line_colors='gray', line_width=2, line_alpha=0.6, point_size=0)

# 绘制分类散点
for g in np.unique(group):
    ix = group == g
    ax.scatter(scatter_x[ix], scatter_y[ix], c=cdict[g], label=g, s=100)

# 补充无限远区域的闭合边界
for region_idx, region in enumerate(vor.regions):
    # 跳过空区域和无无限远顶点的区域
    if not region or -1 not in region:
        continue
    # 获取对应的数据点中心,判断边界延伸方向
    point_idx = vor.point_region.index(region_idx)
    point_center = centers2[point_idx]
    
    vertices = []
    for v_idx in region:
        if v_idx == -1:
            # 根据中心位置,添加坐标轴边界点
            if point_center[0] < (x_min + x_max)/2:
                vertices.append([x_min, point_center[1]])
            else:
                vertices.append([x_max, point_center[1]])
            if point_center[1] < (y_min + y_max)/2:
                vertices.append([point_center[0], y_min])
            else:
                vertices.append([point_center[0], y_max])
        else:
            vertices.append(vor.vertices[v_idx])
    # 绘制闭合多边形
    polygon = plt.Polygon(vertices, fill=False, edgecolor='gray', linewidth=2, alpha=0.6)
    ax.add_patch(polygon)

# 设置坐标轴范围和标签
ax.set_xlim(x_min, x_max)
ax.set_ylim(y_min, y_max)
ax.set_xlabel('d')
ax.set_ylabel('p')
ax.legend()
plt.title('Voronoi Diagram with Complete Boundaries')

plt.show()
plt.close()

关键说明

  • 处理无限远顶点时,通过对应数据点的中心位置判断边界延伸方向,确保Voronoi区域闭合。
  • 给数据范围留10%的余量,避免图形紧贴坐标轴边缘。
  • 按「Voronoi线条→散点→补充边界」的顺序绘图,确保图层显示正常。

内容的提问来源于stack exchange,提问作者quant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 15:02:13