确定布尔函数的外轮廓
Determine outer contour of boolean function
我想确定定义在两个变量上的布尔函数的轮廓,每个变量都在 0、1 范围内。我无权访问该函数的显式形式:它是一个黑框,每对变量 returns 一个布尔值,所以我不知道如何将它转换为连续函数并使用第一个下面回答。该区域是凸的,它可能到达参数范围的边缘。语言是 python。该函数的计算成本可能很高,因此我在下面使用的强力网格方法除了不准确之外还很慢。我该如何改进?
import numpy as np
import matplotlib.pyplot as plt
def f(x, y): return ((x-0.3)**2+(y-0.4)**2 <= 0.1) # Example of function; may extend outside region. In reality, form is not known.
xs, ys = np.linspace(0, 1, 11), np.linspace(0, 1, 11) # Brute force grid
for x in xs:
for y in ys: plt.plot(x, y, 'ro' if f(x, y) else 'b+')
cntr = [] # List of unique, approximate contour points
for x in xs:
col = [y for y in ys if f(x, y)]
if (col != []) and (not ((x, min(col)) in cntr)): cntr.append((x, min(col)))
if (col != []) and (not ((x, max(col)) in cntr)): cntr.append((x, max(col)))
for y in ys:
row = [x for x in xs if f(x, y)]
if (row != []) and (not ((min(row), y) in cntr)): cntr.append((min(row), y))
if (row != []) and (not ((max(row), y) in cntr)): cntr.append((max(row), y))
plt.plot(np.transpose(cntr)[0], np.transpose(cntr)[1], 'kv') # Contour in black
plt.show()
编辑:级别对@Arne 回答的影响说明:
当然,这总是有点近似,因为您无法对每个点进行采样,但是有两个函数可以帮助简化代码并加快速度:np.meshgrid()
and plt.contour()
。后者允许指定要绘制的 levels
,因此您可以通过将阈值保留在布尔函数之外来定义实值函数,并将阈值作为要绘制的级别传递给 plt.contour()
:
import numpy as np
import matplotlib.pyplot as plt
def f_continuous(x, y):
return (x - 0.3)**2 + (y - 0.4)**2 # real-valued instead of Boolean;
# define the 0.1 threshold in the contour plot function instead
xs, ys = np.linspace(0, 1, 11), np.linspace(0, 1, 11) # Brute force grid
X, Y = np.meshgrid(xs, ys)
plt.contour(X, Y, f_continuous(X, Y), levels=[0.1])
plt.show()
编辑:如果函数是黑盒,不能变成连续的怎么办?
您仍然可以使用 plt.contour()
,方法是传递一个介于布尔值 0 和 1 之间的值作为轮廓级别。在这种情况下,插值结果并不平滑:
plt.contour(X, Y, f(X, Y), levels=[0.5])
plt.show()
作为您链接到笔记的答案,您可以通过捕获 plt.contour()
返回的 QuadContourSet
对象并访问其 allsegs
来获取轮廓线上计算点的坐标属性:
contour = plt.contour(X, Y, f(X, Y), levels=[0.5])
contour.allsegs
[[array([[0. , 0.25],
[0.05, 0.2 ],
[0.1 , 0.15],
...
[0.1 , 0.65],
[0.05, 0.6 ],
[0. , 0.55]])]]
我想确定定义在两个变量上的布尔函数的轮廓,每个变量都在 0、1 范围内。我无权访问该函数的显式形式:它是一个黑框,每对变量 returns 一个布尔值,所以我不知道如何将它转换为连续函数并使用第一个下面回答。该区域是凸的,它可能到达参数范围的边缘。语言是 python。该函数的计算成本可能很高,因此我在下面使用的强力网格方法除了不准确之外还很慢。我该如何改进?
import numpy as np
import matplotlib.pyplot as plt
def f(x, y): return ((x-0.3)**2+(y-0.4)**2 <= 0.1) # Example of function; may extend outside region. In reality, form is not known.
xs, ys = np.linspace(0, 1, 11), np.linspace(0, 1, 11) # Brute force grid
for x in xs:
for y in ys: plt.plot(x, y, 'ro' if f(x, y) else 'b+')
cntr = [] # List of unique, approximate contour points
for x in xs:
col = [y for y in ys if f(x, y)]
if (col != []) and (not ((x, min(col)) in cntr)): cntr.append((x, min(col)))
if (col != []) and (not ((x, max(col)) in cntr)): cntr.append((x, max(col)))
for y in ys:
row = [x for x in xs if f(x, y)]
if (row != []) and (not ((min(row), y) in cntr)): cntr.append((min(row), y))
if (row != []) and (not ((max(row), y) in cntr)): cntr.append((max(row), y))
plt.plot(np.transpose(cntr)[0], np.transpose(cntr)[1], 'kv') # Contour in black
plt.show()
编辑:级别对@Arne 回答的影响说明:
当然,这总是有点近似,因为您无法对每个点进行采样,但是有两个函数可以帮助简化代码并加快速度:np.meshgrid()
and plt.contour()
。后者允许指定要绘制的 levels
,因此您可以通过将阈值保留在布尔函数之外来定义实值函数,并将阈值作为要绘制的级别传递给 plt.contour()
:
import numpy as np
import matplotlib.pyplot as plt
def f_continuous(x, y):
return (x - 0.3)**2 + (y - 0.4)**2 # real-valued instead of Boolean;
# define the 0.1 threshold in the contour plot function instead
xs, ys = np.linspace(0, 1, 11), np.linspace(0, 1, 11) # Brute force grid
X, Y = np.meshgrid(xs, ys)
plt.contour(X, Y, f_continuous(X, Y), levels=[0.1])
plt.show()
编辑:如果函数是黑盒,不能变成连续的怎么办?
您仍然可以使用 plt.contour()
,方法是传递一个介于布尔值 0 和 1 之间的值作为轮廓级别。在这种情况下,插值结果并不平滑:
plt.contour(X, Y, f(X, Y), levels=[0.5])
plt.show()
作为您链接到笔记的答案,您可以通过捕获 plt.contour()
返回的 QuadContourSet
对象并访问其 allsegs
来获取轮廓线上计算点的坐标属性:
contour = plt.contour(X, Y, f(X, Y), levels=[0.5])
contour.allsegs
[[array([[0. , 0.25],
[0.05, 0.2 ],
[0.1 , 0.15],
...
[0.1 , 0.65],
[0.05, 0.6 ],
[0. , 0.55]])]]