diff --git a/libpysal/weights/gabriel.py b/libpysal/weights/gabriel.py index cd3276616..3402b27bc 100644 --- a/libpysal/weights/gabriel.py +++ b/libpysal/weights/gabriel.py @@ -1,7 +1,11 @@ -from scipy.spatial import Delaunay as _Delaunay +import warnings + +import numpy +import pandas from scipy import sparse -from libpysal.weights import W, WSP -import pandas, numpy, warnings +from scipy.spatial import Delaunay as _Delaunay + +from libpysal.weights import WSP, W try: from numba import njit @@ -51,12 +55,13 @@ class Delaunay(W): def __init__(self, coordinates, **kwargs): try: - from numba import njit + from numba import njit # noqa F401 except ModuleNotFoundError: warnings.warn( "The numba package is used extensively in this module" " to accelerate the computation of graphs. Without numba," - " these computations may become unduly slow on large data." + " these computations may become unduly slow on large data.", + stacklevel=2, ) edges, _ = self._voronoi_edges(coordinates) ids = kwargs.get("ids") @@ -144,7 +149,7 @@ def from_dataframe(cls, df, geom_col=None, ids=None, use_index=None, **kwargs): f" but this delaunay triangulation is only well-defined for points." f" Choose a method to convert your dataframe into points (like using" f" the df.centroid) and use that to estimate this graph." - ) + ) from None class Gabriel(Delaunay): @@ -173,12 +178,13 @@ class Gabriel(Delaunay): def __init__(self, coordinates, **kwargs): try: - from numba import njit + from numba import njit # noqa F401 except ModuleNotFoundError: warnings.warn( "The numba package is used extensively in this module" " to accelerate the computation of graphs. Without numba," - " these computations may become unduly slow on large data." + " these computations may become unduly slow on large data.", + stacklevel=2, ) edges, dt = self._voronoi_edges(coordinates) droplist = _filter_gabriel( @@ -198,7 +204,7 @@ def __init__(self, coordinates, **kwargs): W.__init__(self, gabriel_neighbors, id_order=list(ids), **kwargs) -class Relative_Neighborhood(Delaunay): +class Relative_Neighborhood(Delaunay): # noqa N801 """ Constructs the Relative Neighborhood graph from a set of points. This graph is a subset of the Delaunay triangulation, where only @@ -206,11 +212,11 @@ class Relative_Neighborhood(Delaunay): the Minimum Spanning Tree, with additional "relative neighbors" introduced. - A relative neighbor pair of points i,j must be closer than the - maximum distance between i (or j) and each other point k. - This means that the points are at least as close to one another - as they are to any other point. - + A relative neighbor pair of points i,j must be closer than the + maximum distance between i (or j) and each other point k. + This means that the points are at least as close to one another + as they are to any other point. + Parameters ---------- coordinates : array of points, (N,2) @@ -222,16 +228,17 @@ class Relative_Neighborhood(Delaunay): def __init__(self, coordinates, binary=True, **kwargs): try: - from numba import njit + from numba import njit # noqa F401 except ModuleNotFoundError: warnings.warn( "The numba package is used extensively in this module" " to accelerate the computation of graphs. Without numba," - " these computations may become unduly slow on large data." + " these computations may become unduly slow on large data.", + stacklevel=2, ) edges, dt = self._voronoi_edges(coordinates) output, dkmax = _filter_relativehood(edges, dt.points, return_dkmax=False) - row, col, data = zip(*output) + row, col, data = zip(*output, strict=True) if binary: data = numpy.ones_like(col, dtype=float) sp = sparse.csc_matrix((data, (row, col))) # TODO: faster way than this? @@ -288,7 +295,6 @@ def _filter_gabriel(edges, coordinates): in order to construct the Gabriel graph. """ edge_pointer = 0 - n = edges.max() n_edges = len(edges) to_drop = [] while edge_pointer < n_edges: @@ -328,9 +334,7 @@ def _filter_relativehood(edges, coordinates, return_dkmax=False): 3. for each edge of the delaunay (i,j), prune if any dkmax is greater than d(i,j) """ - edge_pointer = 0 n = edges.max() - n_edges = len(edges) out = [] r = [] for edge in edges: diff --git a/libpysal/weights/raster.py b/libpysal/weights/raster.py index 90ea91388..c4a17785f 100644 --- a/libpysal/weights/raster.py +++ b/libpysal/weights/raster.py @@ -1,3 +1,5 @@ +# ruff: noqa: B006, N802 + from .util import lat2SW from .weights import WSP, W import numpy as np @@ -18,7 +20,6 @@ def intercepted_function(f, *f_args, **f_kwargs): return intercepted_function - else: from ..common import jit @@ -51,7 +52,8 @@ def da2W( coords_labels : dictionary Pass dimension labels for coordinates and layers if they do not belong to default dimensions, which are (band/time, y/lat, x/lon) - e.g. coords_labels = {"y_label": "latitude", "x_label": "longitude", "z_label": "year"} + e.g. coords_labels = {"y_label": "latitude", + "x_label": "longitude", "z_label": "year"} Default is {} empty dictionary. k : int Order of contiguity, this will select all neighbors upto kth order. @@ -78,7 +80,6 @@ def da2W( Examples -------- - >>> from libpysal.weights.raster import da2W, testDataArray >>> da = testDataArray().rename( {'band': 'layer', 'x': 'longitude', 'y': 'latitude'}) @@ -119,7 +120,8 @@ def da2W( "xarray.DataArray (raster) object. This computation " "can be very slow and not scale well. It is recommended, " "if possible, to instead build WSP object, which is more " - "efficient and faster. You can do this by using da2WSP method." + "efficient and faster. You can do this by using da2WSP method.", + stacklevel=2, ) wsp = da2WSP(da, criterion, z_value, coords_labels, k, include_nodata, n_jobs) w = wsp.to_W(**kwargs) @@ -154,7 +156,8 @@ def da2WSP( coords_labels : dictionary Pass dimension labels for coordinates and layers if they do not belong to default dimensions, which are (band/time, y/lat, x/lon) - e.g. coords_labels = {"y_label": "latitude", "x_label": "longitude", "z_label": "year"} + e.g. coords_labels = {"y_label": "latitude", + "x_label": "longitude", "z_label": "year"} Default is {} empty dictionary. k : int Order of contiguity, this will select all neighbors upto kth order. @@ -225,7 +228,7 @@ def da2WSP( da = da[slice_dict] ser = da.to_series() - dtype = np.int32 if (shape[0] * shape[1]) < 46340 ** 2 else np.int64 + dtype = np.int32 if (shape[0] * shape[1]) < 46340**2 else np.int64 if "nodatavals" in da.attrs and da.attrs["nodatavals"]: mask = (ser != da.attrs["nodatavals"][0]).to_numpy() ids = np.where(mask)[0] @@ -243,7 +246,8 @@ def da2WSP( warn( "numba cannot be imported, parallel processing " "and include_nodata functionality will be disabled. " - "falling back to slower method" + "falling back to slower method", + stacklevel=2, ) include_nodata = False # Fallback method to build sparse matrix @@ -292,7 +296,7 @@ def da2WSP( # then eliminate zeros from the data. This changes the # sparcity of the csr_matrix !! if k > 1 and not include_nodata: - sw = sum(map(lambda x: sw ** x, range(1, k + 1))) + sw = sum(map(lambda x: sw**x, range(1, k + 1))) sw.setdiag(0) sw.eliminate_zeros() sw.data[:] = np.ones_like(sw.data, dtype=np.int8) @@ -332,7 +336,6 @@ def w2da(data, w, attrs={}, coords=None): >>> w = da2W(da, z_value=2) >>> data = np.random.randint(0, 255, len(w.index)) >>> da1 = w2da(data, w) - """ if not isinstance(w, W): raise TypeError("w must be an instance of weights.W") @@ -340,7 +343,8 @@ def w2da(data, w, attrs={}, coords=None): da = _index2da(data, w.index, attrs, coords) else: raise AttributeError( - "This method requires `w` object to include `index` attribute that is built as a `pandas.MultiIndex` object." + "This method requires `w` object to include `index` " + "attribute that is built as a `pandas.MultiIndex` object." ) return da @@ -375,7 +379,6 @@ def wsp2da(data, wsp, attrs={}, coords=None): >>> wsp = da2WSP(da, z_value=2) >>> data = np.random.randint(0, 255, len(wsp.index)) >>> da1 = w2da(data, wsp) - """ if not isinstance(wsp, WSP): raise TypeError("wsp must be an instance of weights.WSP") @@ -383,7 +386,8 @@ def wsp2da(data, wsp, attrs={}, coords=None): da = _index2da(data, wsp.index, attrs, coords) else: raise AttributeError( - "This method requires `wsp` object to include `index` attribute that is built as a `pandas.MultiIndex` object." + "This method requires `wsp` object to include `index` " + "attribute that is built as a `pandas.MultiIndex` object." ) return da @@ -415,7 +419,9 @@ def testDataArray(shape=(3, 4, 4), time=False, rand=False, missing_vals=True): try: from xarray import DataArray except ImportError: - raise ModuleNotFoundError("xarray must be installed to use this functionality") + raise ModuleNotFoundError( + "xarray must be installed to use this functionality" + ) from None if not rand: np.random.seed(12345) coords = {} @@ -457,7 +463,8 @@ def _da_checker(da, z_value, coords_labels): coords_labels : dictionary Pass dimension labels for coordinates and layers if they do not belong to default dimensions, which are (band/time, y/lat, x/lon) - e.g. coords_labels = {"y_label": "latitude", "x_label": "longitude", "z_label": "year"} + e.g. coords_labels = {"y_label": "latitude"," + "x_label": "longitude", "z_label": "year"} Default is {} empty dictionary. Returns @@ -470,7 +477,9 @@ def _da_checker(da, z_value, coords_labels): try: from xarray import DataArray except ImportError: - raise ModuleNotFoundError("xarray must be installed to use this functionality") + raise ModuleNotFoundError( + "xarray must be installed to use this functionality" + ) from None if not isinstance(da, DataArray): raise TypeError("da must be an instance of xarray.DataArray") @@ -502,7 +511,10 @@ def _da_checker(da, z_value, coords_labels): z_id = 1 if z_value is None: if da.sizes[def_labels["z_label"]] != 1: - warn("Multiple layers detected. Using first layer as default.") + warn( + "Multiple layers detected. Using first layer as default.", + stacklevel=2, + ) else: z_id += tuple(da[def_labels["z_label"]]).index(z_value) else: @@ -533,7 +545,9 @@ def _index2da(data, index, attrs, coords): try: from xarray import DataArray except ImportError: - raise ModuleNotFoundError("xarray must be installed to use this functionality") + raise ModuleNotFoundError( + "xarray must be installed to use this functionality" + ) from None data = np.array(data).flatten() idx = index @@ -555,7 +569,7 @@ def _index2da(data, index, attrs, coords): data_complete = np.empty(shape, data.dtype) data_complete[indexer] = data coords = {} - for dim, lev in zip(dims, idx.levels): + for dim, lev in zip(dims, idx.levels, strict=True): coords[dim] = lev.to_numpy() else: fill = attrs["nodatavals"][0] if "nodatavals" in attrs else 0 @@ -851,7 +865,7 @@ def _parSWbuilder( delayed(_compute_chunk)(nrows, ncols, *ids, id_map, criterion, k, dtype) for ids in chunk ) - rows, cols = zip(*worker_out) + rows, cols = zip(*worker_out, strict=True) rows = np.concatenate(rows) cols = np.concatenate(cols) data = np.ones_like(rows, dtype=np.int8) diff --git a/libpysal/weights/set_operations.py b/libpysal/weights/set_operations.py index dbbabc423..ee8a7a369 100644 --- a/libpysal/weights/set_operations.py +++ b/libpysal/weights/set_operations.py @@ -2,12 +2,19 @@ Set-like manipulation of weights matrices. """ -__author__ = "Sergio J. Rey , Charles Schmidt , David Folch , Dani Arribas-Bel " +__author__ = ( + "Sergio J. Rey , " + "Charles Schmidt , " + "David Folch , " + "Dani Arribas-Bel " +) import copy -from .weights import W, WSP -from scipy.sparse import isspmatrix_csr + from numpy import ones +from scipy.sparse import isspmatrix_csr + +from .weights import WSP, W __all__ = [ "w_union", @@ -26,7 +33,6 @@ def w_union(w1, w2, **kwargs): Parameters ---------- - w1 : W object w2 : W @@ -36,7 +42,6 @@ def w_union(w1, w2, **kwargs): Returns ------- - w : W object @@ -48,7 +53,6 @@ def w_union(w1, w2, **kwargs): Examples -------- - Construct rook weights matrices for two regions, one is 4x4 (16 areas) and the other is 6x4 (24 areas). A union of these two weights matrices results in the new weights matrix matching the larger one. @@ -65,7 +69,6 @@ def w_union(w1, w2, **kwargs): [11, 14, 19] >>> w.neighbors[15] [19, 11, 14] - """ neighbors = dict(list(w1.neighbors.items())) for i in w2.neighbors: @@ -84,22 +87,21 @@ def w_intersection(w1, w2, w_shape="w1", **kwargs): Parameters ---------- - w1 : W object w2 : W object w_shape : string - Defines the shape of the returned weights matrix. 'w1' returns a - matrix with the same IDs as w1; 'all' returns a matrix with all - the unique IDs from w1 and w2; and 'min' returns a matrix with - only the IDs occurring in both w1 and w2. + Defines the shape of the returned weights matrix. + 'w1' returns a matrix with the same IDs as w1; 'all' + returns a matrix with all the unique IDs from w1 and w2; + and 'min' returns a matrix with only the IDs occurring in + both w1 and w2. **kwargs : keyword arguments optional arguments for :class:`pysal.weights.W` Returns ------- - w : W object @@ -110,7 +112,6 @@ def w_intersection(w1, w2, w_shape="w1", **kwargs): Examples -------- - Construct rook weights matrices for two regions, one is 4x4 (16 areas) and the other is 6x4 (24 areas). An intersection of these two weights matrices results in the new weights matrix matching the smaller one. @@ -127,7 +128,6 @@ def w_intersection(w1, w2, w_shape="w1", **kwargs): [11, 14, 19] >>> w.neighbors[15] [11, 14] - """ if w_shape == "w1": @@ -158,27 +158,26 @@ def w_difference(w1, w2, w_shape="w1", constrained=True, **kwargs): Parameters ---------- - w1 : W object w2 : W object w_shape : string - Defines the shape of the returned weights matrix. 'w1' returns a - matrix with the same IDs as w1; 'all' returns a matrix with all - the unique IDs from w1 and w2; and 'min' returns a matrix with - the IDs occurring in w1 and not in w2. + Defines the shape of the returned weights matrix. + 'w1' returns a matrix with the same IDs as w1; 'all' + returns a matrix with all the unique IDs from w1 and w2; + and 'min' returns a matrix with the IDs occurring in w1 + and not in w2. constrained : boolean - If False then the full set of neighbor pairs in w1 that are - not in w2 are returned. If True then those pairs that would - not be possible if w_shape='min' are dropped. Ignored if - w_shape is set to 'min'. + If False then the full set of neighbor pairs in w1 that + are not in w2 are returned. If True then those pairs that + would not be possible if w_shape='min' are dropped. + Ignored if w_shape is set to 'min'. **kwargs : keyword arguments optional arguments for :class:`pysal.weights.W` Returns ------- - w : W object @@ -189,7 +188,6 @@ def w_difference(w1, w2, w_shape="w1", constrained=True, **kwargs): Examples -------- - Construct rook (w2) and queen (w1) weights matrices for two 4x4 regions (16 areas). A queen matrix has all the joins a rook matrix does plus joins between areas that share a corner. The new matrix formed by the difference @@ -209,7 +207,6 @@ def w_difference(w1, w2, w_shape="w1", constrained=True, **kwargs): [11, 14] >>> w.neighbors[15] [10] - """ if w_shape == "w1": @@ -253,14 +250,14 @@ def w_symmetric_difference(w1, w2, w_shape="all", constrained=True, **kwargs): Parameters ---------- - w1 : W object w2 : W object w_shape : string - Defines the shape of the returned weights matrix. 'all' returns a - matrix with all the unique IDs from w1 and w2; and 'min' returns + Defines the shape of the returned weights matrix. + 'all' returns a matrix with all the unique IDs + from w1 and w2; and 'min' returns a matrix with the IDs not shared by w1 and w2. constrained : boolean If False then the full set of neighbor pairs that are not @@ -272,7 +269,6 @@ def w_symmetric_difference(w1, w2, w_shape="all", constrained=True, **kwargs): Returns ------- - w : W object @@ -283,7 +279,6 @@ def w_symmetric_difference(w1, w2, w_shape="all", constrained=True, **kwargs): Examples -------- - Construct queen weights matrix for a 4x4 (16 areas) region (w1) and a rook matrix for a 6x4 (24 areas) region (w2). The symmetric difference of these two matrices (with w_shape set to 'all' and constrained set to False) @@ -302,7 +297,6 @@ def w_symmetric_difference(w1, w2, w_shape="all", constrained=True, **kwargs): [11, 14, 19] >>> set(w.neighbors[15]) == set([10, 19]) True - """ if w_shape == "all": @@ -347,24 +341,21 @@ def w_subset(w1, ids, **kwargs): Parameters ---------- - w1 : W object ids : list - A list containing the IDs to be include in the returned weights - object. + A list containing the IDs to be include + in the returned weights object. **kwargs : keyword arguments optional arguments for :class:`pysal.weights.W` Returns ------- - w : W object Examples -------- - Construct a rook weights matrix for a 6x4 region (24 areas). By default PySAL assigns integer IDs to the areas in a region. By passing in a list of integers from 0 to 15, the first 16 areas are extracted from the @@ -381,11 +372,10 @@ def w_subset(w1, ids, **kwargs): [11, 14, 19] >>> w.neighbors[15] [11, 14] - """ neighbors = {} - ids_set = set(list(ids)) + ids_set = set(ids) for i in ids: if i in w1.neighbors: neigh_add = ids_set.intersection(set(w1.neighbors[i])) @@ -396,7 +386,7 @@ def w_subset(w1, ids, **kwargs): return W(neighbors, id_order=list(ids), **kwargs) -def w_clip(w1, w2, outSP=True, **kwargs): +def w_clip(w1, w2, outSP=True, **kwargs): # noqa N803 """ Clip a continuous W object (w1) with a different W object (w2) so only cells where w2 has a non-zero value remain with non-zero values in w1. @@ -408,16 +398,18 @@ def w_clip(w1, w2, outSP=True, **kwargs): ---------- w1 : W W, scipy.sparse.csr.csr_matrix - Potentially continuous weights matrix to be clipped. The clipped - matrix wc will have at most the same elements as w1. + Potentially continuous weights matrix to be clipped. + The clipped matrix wc will have at most the same + elements as w1. w2 : W W, scipy.sparse.csr.csr_matrix Weights matrix to use as shell to clip w1. Automatically - converted to binary format. Only non-zero elements in w2 will be - kept non-zero in wc. NOTE: assumed to be of the same shape as w1 + converted to binary format. Only non-zero + elements in w2 will be kept non-zero in wc. + NOTE: assumed to be of the same shape as w1 outSP : boolean - If True (default) return sparse version of the clipped W, if - False, return W object of the clipped matrix + If True (default) return sparse version of the clipped W, + if False, return W object of the clipped matrix **kwargs : keyword arguments optional arguments for :class:`pysal.weights.W` @@ -425,7 +417,8 @@ def w_clip(w1, w2, outSP=True, **kwargs): ------- wc : W W, scipy.sparse.csr.csr_matrix - Clipped W object (sparse if outSP=Ture). It inherits ``id_order`` from w1. + Clipped W object (sparse if outSP=Ture). + It inherits ``id_order`` from w1. Examples -------- @@ -474,7 +467,6 @@ def w_clip(w1, w2, outSP=True, **kwargs): [0. , 0. , 0. , 0. , 0. , 0. ]]) - If we wanted an original W object, we can control that with the argument ``outSP``: @@ -502,7 +494,6 @@ def w_clip(w1, w2, outSP=True, **kwargs): [ True, True, True, True, True, True], [ True, True, True, True, True, True], [ True, True, True, True, True, True]]) - """ from .util import WSP2W