def nodes_kdtree(self, only_coords=False): """ Build a kdtree from the network node coords for observations lookup. Parameters ---------- only_coords : bool Flag for only coordinated being passed in. Returns ------- kdtree : scipy.spatial.kdtree.KDTree All network nodes lookup. """ if only_coords: geoms = self.n_data[self.geo_col] coords = list(zip(geoms.x, geoms.y)) kdtree = cg.KDTree(coords) else: coords = [ coords[0] for (node, coords) in list(self.node2coords.items()) ] kdtree = cg.KDTree(coords) return kdtree
def build_net_nodes_kdtree(nodes, only_coords=False): """build a kdtree from the network node coords for point pattern lookup Parameters ---------- node : either nodes2coords dictionary or coords list only_coords : bool Returns ------- net_nodes_kdtree : scipy.spatial.kdtree.KDTree all network nodes lookup """ if only_coords: return cg.KDTree(nodes) else: if type(nodes) is dict: node_coords = [coords[0] for node, coords in list(nodes.items())] elif type(nodes) is list: node_coords = [coords[0] for (node, coords) in nodes] net_nodes_kdtree = cg.KDTree(node_coords) return net_nodes_kdtree
def snap_points_to_links(points, links): """Place points onto closest link in a set of links (arc/edges) Parameters ---------- points : dict Point id as key and (x,y) coordinate as value links : list Elements are of type libpysal.cg.shapes.Chain ** Note ** each element is a links represented as a chain with *one head and one tail vertex* in other words one link only. Returns ------- point2link : dict key [point id (see points in arguments)]; value [a 2-tuple ((head, tail), point) where (head, tail) is the target link, and point is the snapped location on the link. Examples -------- >>> import spaghetti as spgh >>> from libpysal.cg.shapes import Point, Chain >>> points = {0: Point((1,1))} >>> link = [Chain([Point((0,0)), Point((2,0))])] >>> spgh.util.snap_points_to_links(points, link) {0: ([(0.0, 0.0), (2.0, 0.0)], array([1., 0.]))} """ # instantiate an rtree rtree = cg.Rtree() # set the smallest possible float epsilon on machine SMALL = np.finfo(float).eps # initialize network vertex to link lookup vertex_2_link = {} # iterate over network links for link in links: # extract network link (x,y) vertex coordinates head, tail = link.vertices x0, y0 = head x1, y1 = tail if (x0, y0) not in vertex_2_link: vertex_2_link[(x0, y0)] = [] if (x1, y1) not in vertex_2_link: vertex_2_link[(x1, y1)] = [] vertex_2_link[(x0, y0)].append(link) vertex_2_link[(x1, y1)].append(link) # minimally increase the bounding box exterior bx0, by0, bx1, by1 = link.bounding_box bx0 -= SMALL by0 -= SMALL bx1 += SMALL by1 += SMALL # create a rectangle rect = cg.Rect(bx0, by0, bx1, by1) # insert the network link and its associated # rectangle into the rtree rtree.insert(link, rect) # build a KDtree on link vertices kdtree = cg.KDTree(list(vertex_2_link.keys())) point2link = {} for pt_idx, point in points.items(): # first, find nearest neighbor link vertices for the point dmin, vertex = kdtree.query(point, k=1) vertex = tuple(kdtree.data[vertex]) closest = vertex_2_link[vertex][0].vertices # Use this link as the candidate closest link: closest # Use the distance as the distance to beat: dmin point2link[pt_idx] = (closest, np.array(vertex)) x0 = point[0] - dmin y0 = point[1] - dmin x1 = point[0] + dmin y1 = point[1] + dmin # Find all links with bounding boxes that intersect # a query rectangle centered on the point with sides # of length dmin * dmin candidates = [cand for cand in rtree.intersection([x0, y0, x1, y1])] dmin += SMALL dmin2 = dmin * dmin # of the candidate arcs, find the nearest to the query point for candidate in candidates: dist2cand, nearp = squared_distance_point_link( point, candidate.vertices) if dist2cand <= dmin2: closest = candidate.vertices dmin2 = dist2cand point2link[pt_idx] = (closest, nearp) return point2link
def knox(s_coords, t_coords, delta, tau, permutations=99, debug=False): """ Knox test for spatio-temporal interaction. :cite:`Knox:1964` Parameters ---------- s_coords : array (n, 2), spatial coordinates. t_coords : array (n, 1), temporal coordinates. delta : float threshold for proximity in space. tau : float threshold for proximity in time. permutations : int, optional the number of permutations used to establish pseudo- significance (the default is 99). debug : bool, optional if true, debugging information is printed (the default is False). Returns ------- knox_result : dictionary contains the statistic (stat) for the test and the associated p-value (pvalue). stat : float value of the knox test for the dataset. pvalue : float pseudo p-value associated with the statistic. counts : int count of space time neighbors. Examples -------- >>> import numpy as np >>> import libpysal as lps >>> from pointpats import SpaceTimeEvents, knox Read in the example data and create an instance of SpaceTimeEvents. >>> path = lps.examples.get_path("burkitt.shp") >>> events = SpaceTimeEvents(path,'T') Set the random seed generator. This is used by the permutation based inference to replicate the pseudo-significance of our example results - the end-user will normally omit this step. >>> np.random.seed(100) Run the Knox test with distance and time thresholds of 20 and 5, respectively. This counts the events that are closer than 20 units in space, and 5 units in time. >>> result = knox(events.space, events.t, delta=20, tau=5, permutations=99) Next, we examine the results. First, we call the statistic from the results dictionary. This reports that there are 13 events close in both space and time, according to our threshold definitions. >>> result['stat'] == 13 True Next, we look at the pseudo-significance of this value, calculated by permuting the timestamps and rerunning the statistics. In this case, the results indicate there is likely no space-time interaction between the events. >>> print("%2.2f"%result['pvalue']) 0.17 """ # Do a kdtree on space first as the number of ties (identical points) is # likely to be lower for space than time. kd_s = cg.KDTree(s_coords) neigh_s = kd_s.query_pairs(delta) tau2 = tau * tau ids = np.array(list(neigh_s)) # For the neighboring pairs in space, determine which are also time # neighbors d_t = (t_coords[ids[:, 0]] - t_coords[ids[:, 1]])**2 n_st = sum(d_t <= tau2) knox_result = {'stat': n_st[0]} if permutations: joint = np.zeros((permutations, 1), int) for p in range(permutations): np.random.shuffle(t_coords) d_t = (t_coords[ids[:, 0]] - t_coords[ids[:, 1]])**2 joint[p] = np.sum(d_t <= tau2) larger = sum(joint >= n_st[0]) if (permutations - larger) < larger: larger = permutations - larger p_sim = (larger + 1.) / (permutations + 1.) knox_result['pvalue'] = p_sim return knox_result
def snap_points_on_segments(points, segments): """Place points onto closet segment in a set of segments Parameters ---------- points : dict Point id as key and (x,y) coordinate as value segments : list Elements are of type libpysal.cg.shapes.Chain ** Note ** each element is a segment represented as a chain with *one head and one tail node* in other words one link only. Returns ------- p2s : dict key [point id (see points in arguments)]; value [a 2-tuple ((head, tail), point) where (head, tail) is the target segment, and point is the snapped location on the segment. Examples -------- >>> import spaghetti as spgh >>> from libpysal.cg.shapes import Point, Chain >>> points = {0: Point((1,1))} >>> segments = [Chain([Point((0,0)), Point((2,0))])] >>> spgh.util.snap_points_on_segments(points, segments) {0: ([(0.0, 0.0), (2.0, 0.0)], array([1., 0.]))} """ # Put segments in an Rtree. rt = cg.Rtree() SMALL = np.finfo(float).eps node2segs = {} for segment in segments: head, tail = segment.vertices x0, y0 = head x1, y1 = tail if (x0, y0) not in node2segs: node2segs[(x0, y0)] = [] if (x1, y1) not in node2segs: node2segs[(x1, y1)] = [] node2segs[(x0, y0)].append(segment) node2segs[(x1, y1)].append(segment) x0, y0, x1, y1 = segment.bounding_box x0 -= SMALL y0 -= SMALL x1 += SMALL y1 += SMALL r = cg.Rect(x0, y0, x1, y1) rt.insert(segment, r) # Build a KDtree on segment nodes. kt = cg.KDTree(list(node2segs.keys())) p2s = {} for ptIdx, point in points.items(): # First, find nearest neighbor segment node for the point. dmin, node = kt.query(point, k=1) node = tuple(kt.data[node]) closest = node2segs[node][0].vertices # Use this segment as the candidate closest segment: closest # Use the distance as the distance to beat: dmin p2s[ptIdx] = (closest, np.array(node)) x0 = point[0] - dmin y0 = point[1] - dmin x1 = point[0] + dmin y1 = point[1] + dmin # Find all segments with bounding boxes that intersect # a query rectangle centered on the point with sides of length 2*dmin. candidates = [cand for cand in rt.intersection([x0, y0, x1, y1])] dmin += SMALL dmin2 = dmin * dmin # Of the candidate segments, find the nearest to the query point. for candidate in candidates: dnc, p2b = squared_distance_point_segment(point, candidate.vertices) if dnc <= dmin2: closest = candidate.vertices dmin2 = dnc p2s[ptIdx] = (closest, p2b) return p2s