matplotplotlib contourplot 的 numpy 模拟?

numpy analog of matplotplotlib contourplot?

有一个二维数据数组 data 和两个坐标数组 x, y 我可以在任何给定的地方用 matplotlib 绘制等高线图 level

import numpy as np
import matplotlib.pyplot as plt

x, y = np.linspace(0, 2*np.pi), np.linspace(0, 2*np.pi)
xx, yy = np.meshgrid(x, y)
data = np.sin(xx) * np.sin(yy)
level = 0.5
contour_ = plt.contour(xx, yy, data, levels=[level])
plt.show()

现在,我对绘图并不感兴趣,而是对轮廓的位置感兴趣。例如,我想查看轮廓是否位于 x、y 域内或 'leaks' 外部。

我可以通过调用

获得包含轮廓的 (x, y) 点的 path 对象
contour_path = contour_.collections[0].get_paths()

我的问题是是否有标准工具可以仅使用 numpy 而无需 matplotlib 模块来获取相同(或类似)的信息。既然不涉及阴谋,那就合理了。

如果你只有数据字段,你可以找到大约边界所在的位置;

In [1]: import numpy as np

In [2]: x, y = np.linspace(0, 2*np.pi), np.linspace(0, 2*np.pi)

In [3]: xx, yy = np.meshgrid(x, y)

In [4]: data = np.sin(xx) * np.sin(yy)

In [5]: scan = np.logical_and(data>0.45, data<0.55)

In [6]: a, b = scan.shape

In [7]: for x in range(a):
        for y in range(b):
                if scan[x,y]:
                        print('({}, {}),'.format(x,y), end='')
   ...:             
(4, 10),(4, 11),(4, 12),(4, 13),(4, 14),(4, 15),(5, 7),(5, 8),(5, 9),
(5, 16),(5, 17),(6, 6),(6, 7),(6, 18),(6, 19),(7, 5),(7, 6),(7, 19),
(8, 5),(8, 20),(9, 5),(9, 20),(10, 4),(10, 20),(11, 4),(11, 20),
(12, 4),(12, 20),(13, 4),(13, 20),(14, 4),(14, 20),(15, 4),(15, 20),
(16, 5),(16, 20),(17, 5),(17, 19),(18, 6),(18, 18),(18, 19),(19, 6),
(19, 7),(19, 17),(19, 18),(20, 8),(20, 9),(20, 10),(20, 11),(20, 12),
(20, 13),(20, 14),(20, 15),(20, 16),(29, 33),(29, 34),(29, 35),
(29, 36),(29, 37),(29, 38),(29, 39),(29, 40),(29, 41),(30, 31),
(30, 32),(30, 42),(30, 43),(31, 30),(31, 31),(31, 43),(32, 30),
(32, 44),(33, 29),(33, 44),(34, 29),(34, 45),(35, 29),(35, 45),
(36, 29),(36, 45),(37, 29),(37, 45),(38, 29),(38, 45),(39, 29),
(39, 45),(40, 29),(40, 44),(41, 29),(41, 44),(42, 30),(42, 43),
(42, 44),(43, 30),(43, 31),(43, 42),(43, 43),(44, 32),(44, 33),
(44, 40),(44, 41),(44, 42),(45, 34),(45, 35),(45, 36),(45, 37),
(45, 38),(45, 39),

当然扫描范围太小,你找不到很多点。

In [9]: scan2 = np.logical_and(data>0.49, data<0.51)

In [10]: for x in range(a):
        for y in range(b):
                if scan2[x,y]:
                        print('({}, {}),'.format(x,y), end='')
   ....:             
(4, 12),(5, 17),(7, 19),(9, 20),(12, 4),(17, 5),(19, 7),(20, 9),
(29, 40),(30, 42),(32, 44),(37, 45),(40, 29),(42, 30),(44, 32),
(45, 37),

如果你阅读contour的源代码你会发现Cntr:

from matplotlib._cntr import Cntr

x, y = np.linspace(0, 2*np.pi), np.linspace(0, 2*np.pi)
xx, yy = np.meshgrid(x, y)
data = np.sin(xx) * np.sin(yy)
level = 0.5

cntr = Cntr(xx, yy, data)
res = cntr.trace(level)

res 是一个包含路径和代码的列表。