diff --git a/libpysal/cg/kdtree.py b/libpysal/cg/kdtree.py index d4e7a7082..c050dbf34 100644 --- a/libpysal/cg/kdtree.py +++ b/libpysal/cg/kdtree.py @@ -315,9 +315,9 @@ def sparse_distance_matrix(self, other, max_distance, p=2): * 0.5 ) max_distance = sphere.arcdist2linear(max_distance, self.radius) + FLOAT_EPS * 3 - D = temp_KDTree.sparse_distance_matrix(self, other, max_distance) - D = D.tocoo() - # print D.data - a2l = lambda x: sphere.linear2arcdist(x, self.radius) - # print map(a2l,D.data) - return scipy.sparse.coo_matrix((list(map(a2l, D.data)), (D.row, D.col))).todok() + d = temp_KDTree.sparse_distance_matrix(self, other, max_distance) + d = d.tocoo() + # print d.data + a2l = lambda x: sphere.linear2arcdist(x, self.radius) # noqa: E731 + # print map(a2l,d.data) + return scipy.sparse.coo_matrix((list(map(a2l, d.data)), (d.row, d.col))).todok() diff --git a/libpysal/cg/locators.py b/libpysal/cg/locators.py index a4e2f6abe..4beb5aeec 100644 --- a/libpysal/cg/locators.py +++ b/libpysal/cg/locators.py @@ -494,9 +494,9 @@ def __init__(self, polygons): for polygon in polygons: x = polygon.bounding_box.left y = polygon.bounding_box.lower - X = polygon.bounding_box.right - Y = polygon.bounding_box.upper - self._rtree.insert(polygon, Rect(x, y, X, Y)) + _x = polygon.bounding_box.right + _y = polygon.bounding_box.upper + self._rtree.insert(polygon, Rect(x, y, _x, _y)) def inside(self, query_rectangle): """ @@ -549,7 +549,7 @@ def inside(self, query_rectangle): ] ) ip = [] - GPPI = get_polygon_point_intersect + gppi = get_polygon_point_intersect for poly in res: lower = poly.bounding_box.lower right = poly.bounding_box.right @@ -557,7 +557,7 @@ def inside(self, query_rectangle): left = poly.bounding_box.left p1 = Point((left, lower)) p2 = Point((right, upper)) - if GPPI(qp, p1) and GPPI(qp, p2): + if gppi(qp, p1) and gppi(qp, p2): ip.append(poly) return ip diff --git a/libpysal/cg/polygonQuadTreeStructure.py b/libpysal/cg/polygonQuadTreeStructure.py index e463345f0..075a98407 100644 --- a/libpysal/cg/polygonQuadTreeStructure.py +++ b/libpysal/cg/polygonQuadTreeStructure.py @@ -2,6 +2,9 @@ Quad Tree Structure Class for PySAL_core/cg/shapes.Ring, PySAL_core/cg/shapes.Polygon This structure could speed up the determining of point in polygon process """ + +# ruff: noqa: N999 + __author__ = "Hu Shao" import math diff --git a/libpysal/cg/segmentLocator.py b/libpysal/cg/segmentLocator.py index 8a05c2975..94cfa6a88 100644 --- a/libpysal/cg/segmentLocator.py +++ b/libpysal/cg/segmentLocator.py @@ -1,4 +1,4 @@ -# ruff: noqa: A001, A002, B028, N801, N802 +# ruff: noqa: A002, N802, N806, N999 import math import random @@ -30,7 +30,7 @@ def nearest(self, pt): class SegmentLocator: def __init__(self, segments, nbins=500): - warnings.warn("SegmentLocator " + dep_msg, FutureWarning) + warnings.warn("SegmentLocator " + dep_msg, FutureWarning, stacklevel=2) self.data = segments if hasattr(segments, "bounding_box"): bbox = segments.bounding_box @@ -52,9 +52,11 @@ def nearest(self, pt): return possibles[numpy.argmin(distances)] -class Polyline_Shapefile_SegmentLocator: +class Polyline_Shapefile_SegmentLocator: # noqa: N801 def __init__(self, shpfile, nbins=500): - warnings.warn("Polyline_Shapefile_SegmentLocator " + dep_msg, FutureWarning) + warnings.warn( + "Polyline_Shapefile_SegmentLocator " + dep_msg, FutureWarning, stacklevel=2 + ) self.data = shpfile bbox = Rectangle(*shpfile.bbox) res = max((bbox.right - bbox.left), (bbox.upper - bbox.lower)) / float(nbins) @@ -102,7 +104,7 @@ def __init__(self, bounds, resolution): TODO: complete this doctest >>> g = SegmentGrid(Rectangle(0, 0, 10, 10), 1) """ - warnings.warn("SegmentGrid " + dep_msg, FutureWarning) + warnings.warn("SegmentGrid " + dep_msg, FutureWarning, stacklevel=2) if resolution == 0: raise Exception("Cannot create grid with resolution 0") self.res = resolution @@ -203,20 +205,20 @@ def add(self, segment, id): + str(segment) ) i, j = self.bin_loc(segment.p1, id) - I_, J_ = self.bin_loc(segment.p2, id) + i_, j_ = self.bin_loc(segment.p2, id) self.endMask[i, j] = True - self.endMask[I_, J_] = True + self.endMask[i_, j_] = True res = self.res line = segment.line tiny = res / 1000.0 - for i in range(1 + min(i, I_), max(i, I_)): # noqa: B020 + for i in range(1 + min(i, i_), max(i, i_)): # noqa: B020 # print 'i',i x = self.x_range[0] + (i * res) y = line.y(x) self.bin_loc((x - tiny, y), id) self.bin_loc((x + tiny, y), id) - for j in range(1 + min(j, J_), max(j, J_)): # noqa: B020 + for j in range(1 + min(j, j_), max(j, j_)): # noqa: B020 # print 'j',j y = self.y_range[0] + (j * res) x = line.x(y) @@ -280,25 +282,25 @@ def nearest(self, pt): #### Filter indicies by bounds of the grid. ### filters must be applied one at a time ### I havn't figure out a way to group these - filter = rows >= 0 - rows = rows[filter] - cols = cols[filter] # i >= 0 - filter = rows < self.i_range - rows = rows[filter] - cols = cols[filter] # i < i_range - filter = cols >= 0 - rows = rows[filter] - cols = cols[filter] # j >= 0 - filter = cols < self.j_range - rows = rows[filter] - cols = cols[filter] # j < j_range + filter_ = rows >= 0 + rows = rows[filter_] + cols = cols[filter_] # i >= 0 + filter_ = rows < self.i_range + rows = rows[filter_] + cols = cols[filter_] # i < i_range + filter_ = cols >= 0 + rows = rows[filter_] + cols = cols[filter_] # j >= 0 + filter_ = cols < self.j_range + rows = rows[filter_] + cols = cols[filter_] # j < j_range if DEBUG: - maskCopy = self.mask.copy().astype(float) - maskCopy += self.endMask.astype(float) - maskCopy[rows, cols] += 1 - maskCopy[row, col] += 3 + mask_copy = self.mask.copy().astype(float) + mask_copy += self.endMask.astype(float) + mask_copy[rows, cols] += 1 + mask_copy[row, col] += 3 i = pylab.matshow( - maskCopy, + mask_copy, origin="lower", extent=self.x_range + self.y_range, fignum=1, @@ -320,8 +322,8 @@ def nearest(self, pt): ### The old way... ### previously I was using kd.query_ball_point on, ### but the performance was terrible. - I_ = self.kd2.query_ball_point(grid_loc, radius) - for i in I_: + i_ = self.kd2.query_ball_point(grid_loc, radius) + for i in i_: t = tuple(self.kd.data[i]) possibles.update(self.hash[t]) return list(possibles) @@ -341,16 +343,16 @@ def random_points(n): def combo_check(bins, segments, qpoints): - G = SegmentLocator(segments, bins) - G2 = BruteSegmentLocator(segs) + g = SegmentLocator(segments, bins) + g2 = BruteSegmentLocator(segs) for pt in qpoints: - a = G.nearest(pt) - b = G2.nearest(pt) + a = g.nearest(pt) + b = g2.nearest(pt) if a != b: print(a, b, a == b) global DEBUG DEBUG = True - a = G.nearest(pt) + a = g.nearest(pt) print(a) a = segments[a] b = segments[b] @@ -363,11 +365,11 @@ def combo_check(bins, segments, qpoints): def brute_check(segments, qpoints): # noqa: ARG001 t0 = time.time() - G2 = BruteSegmentLocator(segs) + g2 = BruteSegmentLocator(segs) t1 = time.time() print("Created Brute in %0.4f seconds" % (t1 - t0)) t2 = time.time() - q = list(map(G2.nearest, qpoints)) + q = list(map(g2.nearest, qpoints)) t3 = time.time() print("Brute Found %d matches in %0.4f seconds" % (len(qpoints), t3 - t2)) print("Total Brute Time:", t3 - t0) @@ -377,19 +379,19 @@ def brute_check(segments, qpoints): # noqa: ARG001 def grid_check(bins, segments, qpoints, visualize=False): t0 = time.time() - G = SegmentLocator(segments, bins) + g = SegmentLocator(segments, bins) t1 = time.time() - G.grid.kd # noqa: B018 + g.grid.kd # noqa: B018 t2 = time.time() print("Created Grid in %0.4f seconds" % (t1 - t0)) print("Created KDTree in %0.4f seconds" % (t2 - t1)) if visualize: pylab.matshow( - G.grid.mask, origin="lower", extent=G.grid.x_range + G.grid.y_range + g.grid.mask, origin="lower", extent=g.grid.x_range + g.grid.y_range ) t2 = time.time() - list(map(G.nearest, qpoints)) + list(map(g.nearest, qpoints)) t3 = time.time() print("Grid Found %d matches in %0.4f seconds" % (len(qpoints), t3 - t2)) print("Total Grid Time:", t3 - t0) diff --git a/libpysal/cg/shapes.py b/libpysal/cg/shapes.py index 757793d9d..369c4d7d9 100644 --- a/libpysal/cg/shapes.py +++ b/libpysal/cg/shapes.py @@ -5,11 +5,10 @@ __author__ = "Sergio J. Rey, Xinyue Ye, Charles Schmidt, Andrew Winslow, Hu Shao" -# ruff: noqa: A003, B028, N802, E402 +# ruff: noqa: A003, N802, E402 import math import warnings -from typing import Union from .sphere import arcdist @@ -97,7 +96,7 @@ class Point(Geometry): """ def __init__(self, loc): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) self.__loc = tuple(map(float, loc)) @classmethod @@ -242,7 +241,7 @@ def __hash__(self) -> int: return hash(self.__loc) - def __getitem__(self, *args) -> Union[int, float]: + def __getitem__(self, *args) -> int | float: """Return the coordinate for the given dimension. Parameters @@ -348,7 +347,7 @@ class LineSegment(Geometry): """ def __init__(self, start_pt, end_pt): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) self._p1 = start_pt self._p2 = end_pt self._reset_props() @@ -755,7 +754,7 @@ class VerticalLine(Geometry): """ def __init__(self, x): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) self._x = float(x) self.m = float("inf") self.b = float("nan") @@ -821,14 +820,14 @@ class Line(Geometry): """ def __init__(self, m, b): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) if m == float("inf"): raise ArithmeticError("Slope cannot be infinite.") self.m = float(m) self.b = float(b) - def x(self, y: Union[int, float]) -> float: + def x(self, y: int | float) -> float: """Returns the :math:`x`-value of the line at a particular :math:`y`-value. Parameters @@ -853,7 +852,7 @@ def x(self, y: Union[int, float]) -> float: return (y - self.b) / self.m - def y(self, x: Union[int, float]) -> float: + def y(self, x: int | float) -> float: """Returns the :math:`y`-value of the line at a particular :math:`x`-value. Parameters @@ -903,7 +902,7 @@ class Ray: """ def __init__(self, origin, second_p): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) self.o = origin self.p = second_p @@ -929,7 +928,7 @@ class Chain(Geometry): """ def __init__(self, vertices: list): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) if isinstance(vertices[0], list): self._vertices = list(vertices) else: @@ -1052,10 +1051,10 @@ def len(self) -> int: 4.0 """ - def dist(v1: tuple, v2: tuple) -> Union[int, float]: + def dist(v1: tuple, v2: tuple) -> int | float: return math.hypot(v1[0] - v2[0], v1[1] - v2[1]) - def part_perimeter(p: list) -> Union[int, float]: + def part_perimeter(p: list) -> int | float: return sum([dist(p[i], p[i + 1]) for i in range(len(p) - 1)]) if self._len is None: @@ -1064,12 +1063,12 @@ def part_perimeter(p: list) -> Union[int, float]: return self._len @property - def arclen(self) -> Union[int, float]: + def arclen(self) -> int | float: """Returns the geometric length of the chain computed using 'arcdistance' (meters). """ - def part_perimeter(p: list) -> Union[int, float]: + def part_perimeter(p: list) -> int | float: return sum([arcdist(p[i], p[i + 1]) * 1000.0 for i in range(len(p) - 1)]) if self._arclen is None: @@ -1120,7 +1119,7 @@ class Ring(Geometry): """ def __init__(self, vertices): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) if vertices[0] != vertices[-1]: vertices = vertices[:] + vertices[0:1] # msg = "Supplied vertices do not form a closed ring, " @@ -1142,11 +1141,11 @@ def len(self) -> int: return len(self) @staticmethod - def dist(v1, v2) -> Union[int, float]: + def dist(v1, v2) -> int | float: return math.hypot(v1[0] - v2[0], v1[1] - v2[1]) @property - def perimeter(self) -> Union[int, float]: + def perimeter(self) -> int | float: if self._perimeter is None: dist = self.dist v = self.vertices @@ -1198,7 +1197,7 @@ def bounding_box(self): return self._bounding_box @property - def area(self) -> Union[int, float]: + def area(self) -> int | float: """Returns the area of the ring. Examples @@ -1219,18 +1218,18 @@ def area(self) -> Union[int, float]: return abs(self.signed_area) @property - def signed_area(self) -> Union[int, float]: + def signed_area(self) -> int | float: if self._area is None: vertices = self.vertices x = [v[0] for v in vertices] y = [v[1] for v in vertices] - N = len(self) + n = len(self) - A = 0.0 - for i in range(N - 1): - A += (x[i] + x[i + 1]) * (y[i] - y[i + 1]) - A = A * 0.5 - self._area = -A + a = 0.0 + for i in range(n - 1): + a += (x[i] + x[i + 1]) * (y[i] - y[i + 1]) + a = a * 0.5 + self._area = -a return self._area @@ -1267,16 +1266,16 @@ def centroid(self): vertices = self.vertices x = [v[0] for v in vertices] y = [v[1] for v in vertices] - A = self.signed_area - N = len(self) + a = self.signed_area + n = len(self) cx = 0 cy = 0 - for i in range(N - 1): + for i in range(n - 1): f = x[i] * y[i + 1] - x[i + 1] * y[i] cx += (x[i] + x[i + 1]) * f cy += (y[i] + y[i + 1]) * f - cx = 1.0 / (6 * A) * cx - cy = 1.0 / (6 * A) * cy + cx = 1.0 / (6 * a) * cx + cy = 1.0 / (6 * a) * cy self._centroid = Point((cx, cy)) return self._centroid @@ -1391,7 +1390,7 @@ class Polygon(Geometry): """ def __init__(self, vertices, holes=None): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) self._part_rings = [] self._hole_rings = [] @@ -1537,7 +1536,7 @@ def parts(self) -> list: return [list(part) for part in self._vertices] @property - def perimeter(self) -> Union[int, float]: + def perimeter(self) -> int | float: """Returns the perimeter of the polygon. Examples @@ -1547,13 +1546,15 @@ def perimeter(self) -> Union[int, float]: 4.0 """ - def dist(v1: Union[int, float], v2: Union[int, float]) -> float: + def dist(v1: int | float, v2: int | float) -> float: return math.hypot(v1[0] - v2[0], v1[1] - v2[1]) - def part_perimeter(part) -> Union[int, float]: + def part_perimeter(part) -> int | float: return sum([dist(part[i], part[i + 1]) for i in range(-1, len(part) - 1)]) - sum_perim = lambda part_type: sum([part_perimeter(part) for part in part_type]) + sum_perim = lambda part_type: sum( # noqa: E731 + [part_perimeter(part) for part in part_type] + ) if self._perimeter is None: self._perimeter = sum_perim(self._vertices) + sum_perim(self._holes) @@ -1645,7 +1646,9 @@ def part_area(pv: list) -> float: __area = -area # noqa: F821 return __area - sum_area = lambda part_type: sum([part_area(part) for part in part_type]) + sum_area = lambda part_type: sum( # noqa: E731 + [part_area(part) for part in part_type] + ) _area = sum_area(self._vertices) - sum_area(self._holes) return _area @@ -1670,14 +1673,14 @@ def centroid(self) -> tuple: (5.0353535353535355, 5.0353535353535355) """ - CP = [ring.centroid for ring in self._part_rings] - AP = [ring.area for ring in self._part_rings] - CH = [ring.centroid for ring in self._hole_rings] - AH = [-ring.area for ring in self._hole_rings] + cp = [ring.centroid for ring in self._part_rings] + ap = [ring.area for ring in self._part_rings] + ch = [ring.centroid for ring in self._hole_rings] + ah = [-ring.area for ring in self._hole_rings] - A = AP + AH - cx = sum([pt[0] * area for pt, area in zip(CP + CH, A, strict=True)]) / sum(A) - cy = sum([pt[1] * area for pt, area in zip(CP + CH, A, strict=True)]) / sum(A) + a = ap + ah + cx = sum([pt[0] * area for pt, area in zip(cp + ch, a, strict=True)]) / sum(a) + cy = sum([pt[1] * area for pt, area in zip(cp + ch, a, strict=True)]) / sum(a) return cx, cy @@ -1794,7 +1797,7 @@ class Rectangle(Geometry): """ def __init__(self, left, lower, right, upper): - warnings.warn(dep_msg, FutureWarning) + warnings.warn(dep_msg, FutureWarning, stacklevel=2) if right < left or upper < lower: raise ArithmeticError("Rectangle must have positive area.") self.left = float(left) @@ -1827,8 +1830,8 @@ def __eq__(self, other): return False def __add__(self, other): - x, y, X, Y = self[:] - x1, y2, X1, Y1 = other[:] + x, y, X, Y = self[:] # noqa: N806 + x1, y2, X1, Y1 = other[:] # noqa: N806 return Rectangle( min(self.left, other.left), @@ -1917,7 +1920,7 @@ def set_scale(self, scale): self.upper = center[1] + scale * (self.upper - center[1]) @property - def area(self) -> Union[int, float]: + def area(self) -> int | float: """Returns the area of the Rectangle. Examples @@ -1930,7 +1933,7 @@ def area(self) -> Union[int, float]: return (self.right - self.left) * (self.upper - self.lower) @property - def width(self) -> Union[int, float]: + def width(self) -> int | float: """Returns the width of the Rectangle. Examples @@ -1943,7 +1946,7 @@ def width(self) -> Union[int, float]: return self.right - self.left @property - def height(self) -> Union[int, float]: + def height(self) -> int | float: """Returns the height of the Rectangle. Examples diff --git a/libpysal/cg/sphere.py b/libpysal/cg/sphere.py index fcdef5319..a5b959bc0 100644 --- a/libpysal/cg/sphere.py +++ b/libpysal/cg/sphere.py @@ -403,10 +403,10 @@ def haversine(x): # Lambda functions # degree to radian conversion -d2r = lambda x: x * math.pi / 180.0 +d2r = lambda x: x * math.pi / 180.0 # noqa: E731 # radian to degree conversion -r2d = lambda x: x * 180.0 / math.pi +r2d = lambda x: x * 180.0 / math.pi # noqa: E731 def radangle(p0, p1): @@ -544,15 +544,15 @@ def geointerpolate(p0, p1, t, lonx=True): d = radangle(p0, p1) k = 1.0 / math.sin(d) t = t * d - A = math.sin(d - t) * k - B = math.sin(t) * k + a = math.sin(d - t) * k + b = math.sin(t) * k x0, y0 = d2r(p0[0]), d2r(p0[1]) x1, y1 = d2r(p1[0]), d2r(p1[1]) - x = A * math.cos(y0) * math.cos(x0) + B * math.cos(y1) * math.cos(x1) - y = A * math.cos(y0) * math.sin(x0) + B * math.cos(y1) * math.sin(x1) - z = A * math.sin(y0) + B * math.sin(y1) + x = a * math.cos(y0) * math.cos(x0) + b * math.cos(y1) * math.cos(x1) + y = a * math.cos(y0) * math.sin(x0) + b * math.cos(y1) * math.sin(x1) + z = a * math.sin(y0) + b * math.sin(y1) newpx = r2d(math.atan2(y, x)) newpy = r2d(math.atan2(z, math.sqrt(x * x + y * y))) diff --git a/libpysal/cg/standalone.py b/libpysal/cg/standalone.py index ee25652ab..f94088740 100644 --- a/libpysal/cg/standalone.py +++ b/libpysal/cg/standalone.py @@ -6,7 +6,7 @@ __author__ = "Sergio J. Rey, Xinyue Ye, Charles Schmidt, Andrew Winslow" __credits__ = "Copyright (c) 2005-2009 Sergio J. Rey" -# ruff: noqa: F403, F405 +# ruff: noqa: F403, F405, N803 import copy @@ -406,7 +406,7 @@ def get_polygon_point_intersect(poly, pt): def pt_lies_on_part_boundary(p, vx): vx_range = range(-1, len(vx) - 1) - seg = lambda i: LineSegment(vx[i], vx[i + 1]) + seg = lambda i: LineSegment(vx[i], vx[i + 1]) # noqa: E731 return [i for i in vx_range if get_segment_point_dist(seg(i), p)[0] == 0] != [] ret = None @@ -1155,13 +1155,13 @@ def get_shared_segments(poly1, poly2, bool_ret=False): # get_rectangle_rectangle_intersection inlined for speed. r0 = poly1.bounding_box r1 = poly2.bounding_box - wLeft = max(r0.left, r1.left) - wLower = max(r0.lower, r1.lower) - wRight = min(r0.right, r1.right) - wUpper = min(r0.upper, r1.upper) + w_left = max(r0.left, r1.left) + w_lower = max(r0.lower, r1.lower) + w_right = min(r0.right, r1.right) + w_upper = min(r0.upper, r1.upper) - segmentsA = set() - common = list() + segments_a = set() + common = [] for part in poly1.parts + [p for p in poly1.holes if p]: if part[0] != part[-1]: # not closed @@ -1172,14 +1172,14 @@ def get_shared_segments(poly1, poly2, bool_ret=False): # inlining point_touches_rectangle for speed x, y = a # check if point a is in the bounding box intersection - if x >= wLeft and x <= wRight and y >= wLower and y <= wUpper: + if x >= w_left and x <= w_right and y >= w_lower and y <= w_upper: x, y = b # check if point b is in the bounding box intersection - if x >= wLeft and x <= wRight and y >= wLower and y <= wUpper: + if x >= w_left and x <= w_right and y >= w_lower and y <= w_upper: if a > b: - segmentsA.add((b, a)) + segments_a.add((b, a)) else: - segmentsA.add((a, b)) + segments_a.add((a, b)) a = b _ret_bool = False @@ -1192,11 +1192,11 @@ def get_shared_segments(poly1, poly2, bool_ret=False): for b in islice(part, 1, None): # inlining point_touches_rectangle for speed x, y = a - if x >= wLeft and x <= wRight and y >= wLower and y <= wUpper: + if x >= w_left and x <= w_right and y >= w_lower and y <= w_upper: x, y = b - if x >= wLeft and x <= wRight and y >= wLower and y <= wUpper: + if x >= w_left and x <= w_right and y >= w_lower and y <= w_upper: seg = (b, a) if a > b else (a, b) - if seg in segmentsA: + if seg in segments_a: common.append(LineSegment(*seg)) if bool_ret: _ret_bool = True @@ -1232,7 +1232,7 @@ def distance_matrix(X, p=2.0, threshold=5e7): Returns ------- - D : numpy.ndarray + d : numpy.ndarray An n by :math:`m` :math:`p`-norm distance matrix. Raises @@ -1280,18 +1280,18 @@ def distance_matrix(X, p=2.0, threshold=5e7): n, k = X.shape if (n**2) * 32 > threshold: - D = scipy.spatial.distance_matrix(X, X, p) + d = scipy.spatial.distance_matrix(X, X, p) else: - M = np.ones((n, n)) - D = np.zeros((n, n)) + m = np.ones((n, n)) + d = np.zeros((n, n)) for col in range(k): x = X[:, col] - xM = x * M - dx = xM - xM.T + x_m = x * m + dx = x_m - x_m.T if p % 2 != 0: dx = np.abs(dx) dx2 = dx**p - D += dx2 - D = D ** (1.0 / p) + d += dx2 + d = d ** (1.0 / p) - return D + return d diff --git a/libpysal/cg/tests/test_geoJSON.py b/libpysal/cg/tests/test_geoJSON.py index adef800ef..92c2b0862 100644 --- a/libpysal/cg/tests/test_geoJSON.py +++ b/libpysal/cg/tests/test_geoJSON.py @@ -1,5 +1,7 @@ +# ruff: noqa: N999 + from ... import examples as pysal_examples -from ...io.fileio import FileIO as psopen # noqa: N813 +from ...io.fileio import FileIO from ..shapes import Chain, Point, asShape @@ -10,7 +12,7 @@ def test___init__1(self): """ - shp = psopen(pysal_examples.get_path("NAT.shp"), "r") + shp = FileIO(pysal_examples.get_path("NAT.shp"), "r") multipolygons = [p for p in shp if len(p.parts) > 1] for poly in multipolygons: json = poly.__geo_interface__ diff --git a/libpysal/cg/tests/test_polygonQuadTreeStructure.py b/libpysal/cg/tests/test_polygonQuadTreeStructure.py index c966c6e40..b1228fd64 100644 --- a/libpysal/cg/tests/test_polygonQuadTreeStructure.py +++ b/libpysal/cg/tests/test_polygonQuadTreeStructure.py @@ -1,4 +1,7 @@ """locators Unittest.""" + +# ruff: noqa: N999 + from ..polygonQuadTreeStructure import QuadTreeStructureSingleRing from ..shapes import Ring diff --git a/libpysal/cg/tests/test_segmentLocator.py b/libpysal/cg/tests/test_segmentLocator.py index d98b1f7d4..4d6671411 100644 --- a/libpysal/cg/tests/test_segmentLocator.py +++ b/libpysal/cg/tests/test_segmentLocator.py @@ -1,6 +1,6 @@ """Segment Locator Unittest.""" -# ruff: noqa: F403, F405 +# ruff: noqa: F403, F405, N999 from ..segmentLocator import * from ..shapes import * diff --git a/libpysal/cg/tests/test_standalone.py b/libpysal/cg/tests/test_standalone.py index 89433cc13..304da6d05 100644 --- a/libpysal/cg/tests/test_standalone.py +++ b/libpysal/cg/tests/test_standalone.py @@ -600,6 +600,6 @@ def test_distance_matrix(self): for i in range(0, len(points)): for j in range(i, len(points)): x, y = points[i] - X, Y = points[j] - d = ((x - X) ** 2 + (y - Y) ** 2) ** (0.5) + _x, _y = points[j] + d = ((x - _x) ** 2 + (y - _y) ** 2) ** (0.5) assert dist[i, j] == d diff --git a/libpysal/graph/base.py b/libpysal/graph/base.py index 49862a40a..a52a23add 100644 --- a/libpysal/graph/base.py +++ b/libpysal/graph/base.py @@ -995,9 +995,13 @@ def isolates(self): pandas.Index Index with a subset of observations that do not have any neighbor """ - nulls = self._adjacency[self._adjacency == 0].reset_index(level=1) + nulls = self._adjacency[self._adjacency == 0] # since not all zeros are necessarily isolates, do the focal == neighbor check - return nulls[nulls.index == nulls.neighbor].index.unique() + return ( + nulls[nulls.index.codes[0] == nulls.index.codes[1]] + .index.get_level_values(0) + .unique() + ) @cached_property def unique_ids(self): @@ -1399,6 +1403,22 @@ def subgraph(self, ids): ) ) + def eliminate_zeros(self): + """Remove graph edges with zero weight + Eliminates edges with weight == 0 that do not encode an + isolate. This is useful to clean-up edges that will make + no effect in operations like :meth:`lag`. + Returns + ------- + Graph + subset of Graph with zero-weight edges eliminated + """ + # get a mask for isolates + isolates = self._adjacency.index.codes[0] == self._adjacency.index.codes[1] + # substract isolates from mask of zeros + zeros = (self._adjacency == 0) != isolates + return Graph(self._adjacency[~zeros], is_sorted=True) + def _arrange_arrays(heads, tails, weights, ids=None): """ diff --git a/libpysal/graph/tests/test_base.py b/libpysal/graph/tests/test_base.py index 2dca9b048..3b755abf7 100644 --- a/libpysal/graph/tests/test_base.py +++ b/libpysal/graph/tests/test_base.py @@ -942,6 +942,14 @@ def test_component_labels(self): expected, nybb.component_labels, check_dtype=False ) + def test_eliminate_zeros(self): + adj = self.adjacency_str_binary.copy() + adj["Bronx", "Queens"] = 0 + adj["Queens", "Manhattan"] = 0 + with_zero = graph.Graph(adj) + expected = adj.drop([("Bronx", "Queens"), ("Queens", "Manhattan")]) + pd.testing.assert_series_equal(with_zero.eliminate_zeros()._adjacency, expected) + def test_subgraph(self): knn = graph.Graph.build_knn(self.nybb.set_geometry(self.nybb.centroid), k=2) sub = knn.subgraph(["Staten Island", "Bronx", "Brooklyn"])