我试图想出一个在单位圆圈内绘制n个点的函数,但是我需要将它们充分展开。
即。看起来像这样的东西:
是否可以使用两个参数n
(点数)和min_d
(相距最小距离)编写一个函数,使得这些点为:
a)等距
b)没有成对距离超过给定的min_d
从均匀分布中采样的问题在于,可能发生两点几乎在彼此之上,我不想发生这种情况。我需要这种输入来表示节点集群的网络图。
编辑:我在这里找到了答案:Generator of evenly spaced points in a circle in python,但b)仍然没有找到我。
答案 0 :(得分:3)
在提供此答案时,问题是随机数字。因此,该答案给出了绘制随机数的解决方案。它忽略了之后对该问题所做的任何编辑。
开可以简单地绘制随机点,并且每个点检查是否满足最小距离的条件。如果不是,则可以丢弃该点。这可以在列表填充足够的点或满足某些中断条件之前完成。
import numpy as np
import matplotlib.pyplot as plt
class Points():
def __init__(self,n=10, r=1, center=(0,0), mindist=0.2, maxtrials=1000 ) :
self.success = False
self.n = n
self.r = r
self.center=np.array(center)
self.d = mindist
self.points = np.ones((self.n,2))*10*r+self.center
self.c = 0
self.trials = 0
self.maxtrials = maxtrials
self.tx = "rad: {}, center: {}, min. dist: {} ".format(self.r, center, self.d)
self.fill()
def dist(self, p, x):
if len(p.shape) >1:
return np.sqrt(np.sum((p-x)**2, axis=1))
else:
return np.sqrt(np.sum((p-x)**2))
def newpoint(self):
x = (np.random.rand(2)-0.5)*2
x = x*self.r-self.center
if self.dist(self.center, x) < self.r:
self.trials += 1
if np.all(self.dist(self.points, x) > self.d):
self.points[self.c,:] = x
self.c += 1
def fill(self):
while self.trials < self.maxtrials and self.c < self.n:
self.newpoint()
self.points = self.points[self.dist(self.points,self.center) < self.r,:]
if len(self.points) == self.n:
self.success = True
self.tx +="\n{} of {} found ({} trials)".format(len(self.points),self.n,self.trials)
def __repr__(self):
return self.tx
center =(0,0)
radius = 1
p = Points(n=40,r=radius, center=center)
fig, ax = plt.subplots()
x,y = p.points[:,0], p.points[:,1]
plt.scatter(x,y)
ax.add_patch(plt.Circle(center, radius, fill=False))
ax.set_title(p)
ax.relim()
ax.autoscale_view()
ax.set_aspect("equal")
plt.show()
如果要修复点数,您可以尝试运行找到这个点数来减少距离,直到找到所需的点数。
在下面的例子中,我们正在寻找60个点并以最小距离0.6开始,我们逐步减少0.05,直到找到解决方案。请注意,这不一定是最佳解决方案,因为每个步骤中只有maxtrials
次重试。增加maxtrials
当然会使我们更接近最优,但需要更多的运行时间。
center =(0,0)
radius = 1
mindist = 0.6
step = 0.05
success = False
while not success:
mindist -= step
p = Points(n=60,r=radius, center=center, mindist=mindist)
print p
if p.success:
break
fig, ax = plt.subplots()
x,y = p.points[:,0], p.points[:,1]
plt.scatter(x,y)
ax.add_patch(plt.Circle(center, radius, fill=False))
ax.set_title(p)
ax.relim()
ax.autoscale_view()
ax.set_aspect("equal")
plt.show()
此处找到的解决方案最小距离为0.15。