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

如何在不使用contours函数的情况下绘制平滑曲线边缘的数组图

问题:平滑imshow可视化的区域边缘,避免contours的默认插值问题

我用Python的numpy和matplotlib的imshow函数可视化二维数组,生成的图表不同颜色区域边缘呈锯齿状。想把边缘改成平滑曲线,但contours函数默认会在1(对应x)和3(对应z)之间生成2(对应y)的轮廓,和原始数据不符。有没有其他实现方法?

现有代码如下:

import numpy as np
import matplotlib.pyplot as plt

# Define the input data as a 2D NumPy array
arr = np.array([
    ['x', 'x', 'x', 'y', 'y', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'y', 'y', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'y', 'y', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'y', 'y', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'y', 'z', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z'],
])

# Convert input data to numerical values
num_arr = np.zeros(arr.shape)
num_arr[arr == 'x'] = 1
num_arr[arr == 'y'] = 2
num_arr[arr == 'z'] = 3

# Create a colormap
cmap = plt.get_cmap('viridis', 3)

# Plot the data
plt.imshow(num_arr, cmap=cmap)
plt.colorbar(ticks=[1, 2, 3], format=plt.FuncFormatter(lambda val, loc: {1: 'x', 2: 'y', 3: 'z'}[val]))
plt.title('Graphical Representation of Data')
plt.show()

解决方案:插值提升分辨率+自定义真实边界绘制

核心思路是先对原始低分辨率数据做插值提升清晰度,再只提取真实存在的类别边界(x-y和y-z),避免contours自动生成不存在的中间边界。

完整实现代码

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata

# 原始数据
arr = np.array([
    ['x', 'x', 'x', 'y', 'y', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'y', 'y', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'y', 'y', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'y', 'y', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'y', 'z', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z'],
    ['x', 'x', 'x', 'x', 'x', 'x', 'z', 'z', 'z', 'z', 'z'],
])

# 转数值数组
num_arr = np.zeros(arr.shape)
num_arr[arr == 'x'] = 1
num_arr[arr == 'y'] = 2
num_arr[arr == 'z'] = 3

# --------------------------
# 1. 生成高分辨率网格并插值
# --------------------------
# 原始网格坐标
y_original, x_original = np.mgrid[0:num_arr.shape[0], 0:num_arr.shape[1]]
# 高分辨率网格(这里把分辨率提升10倍,可调整)
resolution_scale = 10
y_high, x_high = np.mgrid[0:num_arr.shape[0]:1j*(num_arr.shape[0]*resolution_scale),
                          0:num_arr.shape[1]:1j*(num_arr.shape[1]*resolution_scale)]
# 用立方插值提升分辨率
interpolated_data = griddata((y_original.flatten(), x_original.flatten()),
                             num_arr.flatten(),
                             (y_high, x_high),
                             method='cubic')

# --------------------------
# 2. 提取真实存在的边界
# --------------------------
# 只绘制x-y(1和2之间)和y-z(2和3之间)的边界,跳过x-z的虚假边界
fig, ax = plt.subplots()
# 绘制插值后的图像
im = ax.imshow(interpolated_data, cmap=plt.get_cmap('viridis', 3),
               extent=[0, num_arr.shape[1], num_arr.shape[0], 0])

# 绘制x-y边界(值为1.5的等高线)
ax.contour(x_high, y_high, interpolated_data, levels=[1.5], colors='white', linewidths=2)
# 绘制y-z边界(值为2.5的等高线)
ax.contour(x_high, y_high, interpolated_data, levels=[2.5], colors='white', linewidths=2)

# --------------------------
# 3. 调整图表样式
# --------------------------
cbar = plt.colorbar(im, ticks=[1, 2, 3])
cbar.ax.set_yticklabels(['x', 'y', 'z'])
plt.title('Smooth Edge Visualization')
plt.show()

关键细节说明

  • 插值提升分辨率:使用scipy.interpolate.griddata的立方插值,把原始低分辨率数据放大到更高精度的网格,让边缘过渡更平滑,避免锯齿。
  • 自定义边界提取:手动指定只绘制1.5(x和y的中间值)和2.5(y和z的中间值)的等高线,完全跳过1.5到2.5之外的虚假边界,保证和原始数据的类别对应关系一致。
  • 样式调整:用白色粗线绘制边界,既突出区域划分,又保持整体视觉协调。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 20:45:06