我一直在寻找一种解决方案来计算周期性/包裹边缘晶格上离散的等距方形点之间的空间距离。例如,在9x9点阵上将相邻站点设置为2个单位:
m = 9
lattice = np.zeros((m,m))
for i in arange(0,6+1,3):
for j in arange(0,6+1,3):
lattice[i,j]=1
In []: lattice
Out []: array([[ 1., 0., 0., 1., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 1., 0., 0., 1., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 1., 0., 0., 1., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
In []: plt.imshow(lattice, origin='origin', cmap='binary', interpolation='none')
其中站点用索引注释,红色箭头表示从站点0(2个单位)的等距离,我如何创建一个数组sdist
,它给出了站点之间最短的成对距离,即sdist[7,1]=2
,{ {1}}。通常的工具sdist[2,6] = 2.8284
似乎不适用于此。
答案 0 :(得分:3)
由于distance.cdist
接受任意度量(以可调用方式提供),因此问题只在于为度量标准编写函数。
如果它是点p和q之间的包裹距离,那将是
def wrapped_euclidean_points(p, q):
diff = np.abs(p - q)
return np.linalg.norm(np.minimum(diff, m - diff))
其中m
是晶格的大小(遗憾的是cdist
不支持将额外的参数传递给距离函数,因此必须从较大的范围中获取m
。)< / p>
但是在你的情况下,你希望边长1的平方之间的距离最小。这意味着在计算包裹差矢量np.minimum(diff, m - diff)
后,我们可以将每个分量减少1,因为,例如,两个正方形的点之间的最小x差异比这些正方形的中心之间的x差异小1。当然,这个减法不应该产生差异负。
因此功能变为
def wrapped_euclidean_squares(p, q):
diff = np.abs(p - q)
return np.linalg.norm(np.clip(np.minimum(diff, m - diff) - 1, 0, None))
其中clip
处理两个中心具有相同x坐标或相同y坐标的情况。
剩下的就是两行(不计算from scipy.spatial import distance
):
coords = np.vstack(np.nonzero(lattice)).T
dist = distance.cdist(coords, coords, metric=wrapped_euclidean_squares)
您的示例的输出:
[[ 0. 2. 2. 2. 2.82842712 2.82842712 2. 2.82842712 2.82842712]
[ 2. 0. 2. 2.82842712 2. 2.82842712 2.82842712 2. 2.82842712]
[ 2. 2. 0. 2.82842712 2.82842712 2. 2.82842712 2.82842712 2. ]
[ 2. 2.82842712 2.82842712 0. 2. 2. 2. 2.82842712 2.82842712]
[ 2.82842712 2. 2.82842712 2. 0. 2. 2.82842712 2. 2.82842712]
[ 2.82842712 2.82842712 2. 2. 2. 0. 2.82842712 2.82842712 2. ]
[ 2. 2.82842712 2.82842712 2. 2.82842712 2.82842712 0. 2. 2. ]
[ 2.82842712 2. 2.82842712 2.82842712 2. 2.82842712 2. 0. 2. ]
[ 2.82842712 2.82842712 2. 2.82842712 2.82842712 2. 2. 2. 0. ]]
答案 1 :(得分:2)
我试图理解这个请求,我的插图在这里说明了
而不是格子点的那些,我从1开始编号。
然后我增加了&#39; lattice
中给出的单元格通过切片并使用np.concatenate
在每个起始点阵的边界上添加半个单元格
图中的黄线表示细胞寄宿生
给定起始格点标签号,我在我的&#39; fullLaug&#39;中找到所有实例。数组和计算平方欧几里德的差异,并按它排序
根据这个例子,我采用最短的方法并绘制一条从起点1
开始的线到其他每个点的最短距离实例&lt; fullLaug&#39;以及打印实际距离
import numpy as np
import matplotlib.pyplot as plt
" create lattice, lattice points nonzero, incremtning count "
m = 9
pcnt = 0
lattice = np.zeros((m, m))
for i in range(0, 6+1, 3):
for j in range(0, 6+1, 3):
pcnt += 1
lattice[i, j] = pcnt # lable lattice points with count
#print(*lattice, sep='\n')
"augment lattice with duplicated halves, up/down, left/right"
def halves(a):
n = len(a)
return a[:(n+n%2)//2-n%2], a[(n-n%2)//2+n%2:]
rightL, leftL = halves(lattice.T)
n = len(rightL)
cornerL = np.zeros((n, n))
rightL, leftL = rightL.T, leftL.T
rightLaug = np.concatenate((cornerL, rightL, cornerL), axis=0)
leftLaug = np.concatenate((cornerL, leftL, cornerL), axis=0)
lowL, upL = halves(lattice)
centerL = np.concatenate((upL, lattice, lowL), axis=0)
fullLaug = np.concatenate((leftLaug, centerL, rightLaug), axis=1)
"plot fully agumented lattice, yellow lines are boarders of cells"
plt.imshow(fullLaug, origin='origin', cmap='jet', interpolation='none')
plt.plot((n, n), (0, 2*n+m-1), 'y', (n+m-1, n+m-1), (2*n+m-1, 0), 'y')
plt.plot((0, 2*n+m-1), (n, n), 'y', (2*n+m-1, 0), (n+m-1, n+m-1), 'y')
#print(*zip(*np.where(fullLaug == 3)))
def distsq(a, b, n):
"""takes lattice point pcnt labels a, b
finds a indices in lattice, offests to indices in fullaug
finds all instances of b indices in fullaug
calcs all a-b distances
returns sorted list of distances, indices, a-a appended to start
"""
a = list(*zip(*np.where(lattice == a)))
a[0] += n; a[1] += n
bz = zip(*np.where(fullLaug == b))
ds = [[(a[0] - b[0])**2 + (a[1] - b[1])**2, [*b]] for b in bz]
return [[0, a]] + sorted(ds, key=lambda x: x[0])
""" plot shortest distance lines from point a to each point in lattice
fill dist_lattice"""
dist_lattice = np.zeros((m, m))
for i in range(1, pcnt + 1):
dps = distsq(1, i, n)[0:2]
dist_lattice[np.where(lattice == i)] = np.sqrt(dps[1][0])
plt.plot(*zip(dps[0][1], dps[1][1]))
np.set_printoptions(precision=4, threshold=1000)
print(dist_lattice)
[[ 0. 0. 0. 3. 0. 0. 3. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 3. 0. 0. 4.2426 0. 0. 4.2426 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 3. 0. 0. 4.2426 0. 0. 6.7082 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. ]]