{"id":9316,"library":"spatial-access","title":"Spatial Access","description":"spatial-access is a Python package designed for measuring spatial accessibility to services. It provides tools to construct road networks, represent facilities and demand points, and compute various accessibility metrics like the Two-Step Floating Catchment Area (2SFCA) method. The current version is 1.0.2, and releases are made as needed to address issues and introduce features.","status":"active","version":"1.0.2","language":"en","source_language":"en","source_url":"https://github.com/GeoDaCenter/spatial_access","tags":["geospatial","network analysis","access","routing","GIS","accessibility"],"install":[{"cmd":"pip install spatial-access","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Fundamental for handling geographic data structures (GeoDataFrames) for networks, facilities, and demand points.","package":"geopandas","optional":false},{"reason":"Used for data manipulation and integration with GeoDataFrames.","package":"pandas","optional":false},{"reason":"Powers the underlying graph representation and algorithms for network analysis.","package":"networkx","optional":false}],"imports":[{"note":"Python import statements use underscores, not hyphens, even if the PyPI package name uses hyphens.","wrong":"import spatial-access","symbol":"spatial_access","correct":"import spatial_access as sa"},{"note":"The Network class is typically accessed via the top-level spatial_access module alias.","symbol":"Network","correct":"network = sa.Network(nodes, edges, 'weight_col')"},{"note":"The Access class is typically accessed via the top-level spatial_access module alias.","symbol":"Access","correct":"access_model = sa.Access(network, facilities, demand, 'facility_col', 'demand_col')"}],"quickstart":{"code":"from shapely.geometry import Point, LineString\nimport geopandas as gpd\nimport pandas as pd\nimport spatial_access as sa\n\n# 1. Create dummy network data (nodes and edges)\n# Nodes represent intersections or endpoints\nnodes_df = pd.DataFrame({\n    'id': [0, 1, 2, 3],\n    'geometry': [Point(0, 0), Point(1, 0), Point(0, 1), Point(1, 1)]\n})\nnodes = gpd.GeoDataFrame(nodes_df, crs=\"EPSG:4326\")\n\n# Edges represent road segments connecting nodes\nedges_df = pd.DataFrame({\n    'id': [0, 1, 2, 3],\n    'from': [0, 0, 1, 2],\n    'to': [1, 2, 3, 3],\n    'length': [1.0, 1.0, 1.0, 1.0], # A 'weight' or 'cost' column\n    'geometry': [\n        LineString([(0, 0), (1, 0)]),\n        LineString([(0, 0), (0, 1)]),\n        LineString([(1, 0), (1, 1)]),\n        LineString([(0, 1), (1, 1)])\n    ]\n})\nedges = gpd.GeoDataFrame(edges_df, crs=\"EPSG:4326\")\n\n# 2. Create dummy facility and demand data\n# Facilities (e.g., hospitals, stores) with capacity\nfacilities_df = pd.DataFrame({\n    'id': [0, 1],\n    'capacity': [10, 15],\n    'geometry': [Point(0.1, 0.1), Point(0.9, 0.9)]\n})\nfacilities = gpd.GeoDataFrame(facilities_df, crs=\"EPSG:4326\")\n\n# Demand points (e.g., population centroids) with demand\ndemand_df = pd.DataFrame({\n    'id': [0, 1],\n    'demand': [5, 8],\n    'geometry': [Point(0.2, 0.2), Point(0.8, 0.8)]\n})\ndemand = gpd.GeoDataFrame(demand_df, crs=\"EPSG:4326\")\n\n\n# 3. Initialize Network and Access objects\n# The 'length' column is used as the weight for shortest path calculations\nnetwork = sa.Network(nodes, edges, \"length\")\n\n# Create the Access model, linking network, facilities, and demand\naccess_model = sa.Access(network, facilities, demand, \"capacity\", \"demand\")\n\n# 4. Compute 2SFCA accessibility\n# Using a distance threshold of 10 units (arbitrary for dummy data)\n# and a Gaussian weight function. The result is (Si, Dj) where Si is \n# accessibility for demand points and Dj for facilities.\nprint(\"Calculating 2SFCA accessibility...\")\naccessibility_scores = access_model.two_sfca(10, weight_function=\"gaussian\")\n\n# Print accessibility scores for demand points\nprint(\"\\nAccessibility scores for demand points (Si):\")\nprint(accessibility_scores[0].head())","lang":"python","description":"This quickstart demonstrates how to create a simple road network, define facilities and demand points using GeoDataFrames, and then compute spatial accessibility using the Two-Step Floating Catchment Area (2SFCA) method. It uses dummy data to ensure the example is runnable out-of-the-box."},"warnings":[{"fix":"Upgrade to version 1.0.2 or newer. Alternatively, ensure your input network is a single connected component or filter to the largest connected component before processing.","message":"Prior to version 1.0.2, the internal C++ Dijkstra implementation could crash when the input road network contained multiple disconnected components, leading to unexpected program termination.","severity":"breaking","affected_versions":"<1.0.2"},{"fix":"Upgrade to version 1.0.2 or newer, which gracefully handles attempts to drop non-existent columns. For older versions, ensure all specified columns for removal actually exist in the DataFrame.","message":"Dropping non-existent columns from a road network GeoDataFrame would previously raise an error, interrupting the workflow.","severity":"gotcha","affected_versions":"<1.0.2"},{"fix":"Always ensure that `nodes`, `edges`, `facilities`, and `demand` GeoDataFrames have a consistent CRS. Reproject them if necessary using `.to_crs()` before creating `Network` or `Access` objects. For example: `gdf.to_crs('EPSG:26918')` for projected coordinates suitable for distance calculations.","message":"Coordinate Reference System (CRS) mismatches between input GeoDataFrames (nodes, edges, facilities, demand) can lead to incorrect distance calculations or errors during spatial operations. All input GeoDataFrames must share the same CRS.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Verify that the column names passed to `sa.Network` and `sa.Access` constructors (e.g., `weight_col`, `facility_col_name`, `demand_col_name`) exactly match the column names in your input GeoDataFrames.","message":"The `spatial_access.Network` object expects specific column names for weights (e.g., 'length', 'travel_time') and the `Access` object expects 'capacity' and 'demand' columns. Using incorrect column names will result in `KeyError`.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure the package is installed via `pip install spatial-access` and then import using `import spatial_access as sa`.","cause":"Attempting to import the library using a hyphen instead of an underscore, or the package is not installed.","error":"ModuleNotFoundError: No module named 'spatial-access'"},{"fix":"Check your input GeoDataFrames (`nodes`, `edges`, `facilities`, `demand`) and ensure they contain the columns specified in the `spatial_access.Network` and `spatial_access.Access` constructors. Column names are case-sensitive.","cause":"A GeoDataFrame provided to `Network` or `Access` is missing a required column (e.g., weight, capacity, demand) that was specified by name.","error":"KeyError: 'some_missing_column_name'"},{"fix":"Pre-process your road network to ensure connectivity. You can often extract the largest connected component using `networkx` functions or similar tools before passing the data to `spatial_access`.","cause":"The road network provided to `spatial_access.Network` is not fully connected (e.g., contains isolated islands of roads), which prevents shortest path calculations between all points.","error":"ValueError: The input network must be connected. Consider filtering to the largest connected component."},{"fix":"Inspect and clean your input GeoDataFrames for invalid geometries. Use `gdf.geometry.is_valid` to identify issues and `gdf.geometry.buffer(0)` or other `shapely` / `geopandas` tools for minor repairs.","cause":"Input geometry data (especially LineStrings in edges) contains invalid or malformed geometries, such as a LineString with identical start and end points, or other self-intersections.","error":"pygeos.GEOSException: IllegalArgumentException: Points of LineString must have distinct coordinates"}]}