Skip to main content
Glama

distance_band_weights

Create spatial weights for point data based on distance thresholds to analyze spatial relationships in GIS applications.

Instructions

Create a distance-based spatial weights (W) object from point data.

  • data_path: path to point shapefile or GeoPackage

  • threshold: distance threshold for neighbors (in CRS units, e.g., meters)

  • binary: True for binary weights, False for inverse distance weights

  • id_field: optional attribute name to use as observation IDs

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
data_pathYes
thresholdYes
binaryNo
id_fieldNo

Implementation Reference

  • The primary handler function implementing the 'distance_band_weights' tool. It loads point data from a shapefile, extracts coordinates, creates a libpysal DistanceBand weights object based on the given threshold and binary option, computes statistics and previews, ensures JSON serialization compatibility by converting numpy types, and returns structured results including weights_info for test compatibility.
    def distance_band_weights(
        data_path: str,
        threshold: float,
        binary: bool = True,
        id_field: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        Create a distance-based spatial weights (W) object from point data.
    
        - data_path: path to point shapefile or GeoPackage
        - threshold: distance threshold for neighbors (in CRS units, e.g., meters)
        - binary: True for binary weights, False for inverse distance weights
        - id_field: optional attribute name to use as observation IDs
        """
        try:
            if not os.path.exists(data_path):
                return {"status": "error", "message": f"Data file not found: {data_path}"}
    
            gdf = gpd.read_file(data_path)
    
            if gdf.empty:
                return {"status": "error", "message": "Input file contains no features"}
    
            # Extract coordinates
            coords = [(geom.x, geom.y) for geom in gdf.geometry]
    
            # Create DistanceBand weights
            import libpysal
            if id_field and id_field in gdf.columns:
                ids = gdf[id_field].tolist()
                w = libpysal.weights.DistanceBand(coords, threshold=threshold, binary=binary, ids=ids)
            else:
                w = libpysal.weights.DistanceBand(coords, threshold=threshold, binary=binary)
    
            ids = w.id_order
            neighbor_counts = [w.cardinalities[i] for i in ids]
            islands = list(w.islands) if hasattr(w, "islands") else []
    
            # Previews - convert to native Python types immediately
            preview_ids = ids[:5]
            neighbors_preview = {}
            weights_preview = {}
            for i in preview_ids:
                # Convert neighbor IDs and weights to native Python types
                neighbors = w.neighbors.get(i, [])
                weights_list = w.weights.get(i, [])
                neighbors_preview[i] = [int(n) if isinstance(n, (np.integer, np.int32, np.int64)) else n for n in neighbors]
                weights_preview[i] = [float(w_val) if isinstance(w_val, (np.floating, np.float32, np.float64)) else (int(w_val) if isinstance(w_val, (np.integer, np.int32, np.int64)) else w_val) for w_val in weights_list]
    
            result = {
                "n": int(w.n),
                "id_count": int(len(ids)),
                "threshold": float(threshold),
                "binary": bool(binary),
                "id_field": id_field,
                "neighbors_stats": {
                    "min": int(min(neighbor_counts)) if neighbor_counts else 0,
                    "max": int(max(neighbor_counts)) if neighbor_counts else 0,
                    "mean": float(np.mean(neighbor_counts)) if neighbor_counts else 0.0,
                },
                "islands": [int(i) if isinstance(i, (np.integer, np.int32, np.int64)) else i for i in islands],
                "neighbors_preview": neighbors_preview,
                "weights_preview": weights_preview,
            }
    
            # Convert numpy types to native Python types for serialization (recursive)
            def convert_numpy_types(obj):
                """Recursively convert numpy types to native Python types."""
                if obj is None:
                    return None
                if isinstance(obj, dict):
                    return {k: convert_numpy_types(v) for k, v in obj.items()}
                elif isinstance(obj, (list, tuple)):
                    return [convert_numpy_types(item) for item in obj]
                elif isinstance(obj, (np.integer, np.int32, np.int64, np.int8, np.int16)):
                    return int(obj)
                elif isinstance(obj, (np.floating, np.float32, np.float64, np.float16)):
                    return float(obj)
                elif isinstance(obj, np.ndarray):
                    return obj.tolist()
                elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes)):
                    # Handle other iterable types
                    return [convert_numpy_types(item) for item in obj]
                else:
                    return obj
            
            result = convert_numpy_types(result)
    
            return {
                "status": "success",
                "message": "DistanceBand spatial weights constructed successfully",
                "result": result,
                "weights_info": result,  # Also include as weights_info for test compatibility
            }
    
        except Exception as e:
            logger.error(f"Error creating DistanceBand weights: {str(e)}")
            return {"status": "error", "message": f"Failed to create DistanceBand weights: {str(e)}"}

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mahdin75/gis-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server