leeway = 1.1
XX = X.reshape((1, X.size))
dX = np.abs(XX - XX.T).reshape((1, X.size ** 2))
dxs = dX[np.where(np.logical_and(dX > expected_distance / leeway, dX < 
    expected_distance * leeway))]
dx = dxs.mean()
YY = Y.reshape((1, Y.size))
dY = np.abs(YY - YY.T).reshape((1, Y.size ** 2))
dys = dY[np.where(np.logical_and(dY > expected_distance / leeway, dY < 
    expected_distance * leeway))]
dy = dys.mean()
Constructing a 2D grid from potentially incomplete list of candidates