# Python (Geopandas)

This example will provide an introduction on how to use OS NGD API – Features to extract and plot OS NGD data! We’ll be using [GeoPandas](https://geopandas.org/en/stable/index.html), a library that builds on Pandas to help manage and analyse spatial data.

### What you'll need

* OS NGD API – Features added to an API project in the OS Data Hub with an API Key. See [Getting started with an API project](https://docs.os.uk/os-apis/core-concepts/getting-started-with-an-api-project) for more information.
* The following dependencies installed:
  * [GeoPandas](https://geopandas.org/en/stable/index.html)
  * [Requests](https://pypi.org/project/requests/)
  * [Shapely](https://pypi.org/project/shapely/)

{% hint style="info" %}
More examples in an executable notebook format are available through our [OS APIs Python wrapper](https://pypi.org/project/osdatahub/).
{% endhint %}

{% stepper %}
{% step %}

### Import the required libraries

```python
import requests
import geopandas as gpd
from shapely.geometry import shape
```

{% endstep %}

{% step %}

### Set up your OS API credentials

```python
# OS NGD API - Features API Key
api_key = "INSERT_API_KEY"

# OS NGD API - Features base URL
base_url = "https://api.os.uk/features/ngd/ofa/v1"

# OS NGD API - Features CollectionId
collection= "wtr-fts-water-2"
```

{% endstep %}

{% step %}

### Request data from OS NGD API – Features

```python
# Define your bounding box
bbox = [-314177.76517933805,6641680.87433119,-304909.7754997604,6653318.411887609] # Example: Glastonbury Canal

# Initialize an empty list to collect all features
all_features = []

# Loop through 20 pages
for page in range(20):
 offset = page * 100  # Calculate the offset based on the page number
 params = {
        "key": api_key,
        "bbox": ",".join(map(str, bbox)),
        "limit": 100,
        "offset": offset,
        "bbox-crs": "http://www.opengis.net/def/crs/EPSG/0/3857",
        "crs": "http://www.opengis.net/def/crs/EPSG/0/3857",
 }

 # Send a request to the OS NGD API - Features
 response = requests.get(f"{base_url}/collections/{collection}/items", params=params)

 # Check if the request was successful
 if response.status_code == 200:
   data = response.json()
   features = data.get("features", [])
   all_features.extend(features)
   if len(features) < params["limit"]:  # Stop as there are no more features to retrieve
     break
 else:
   print(f"Error: {response.status_code}")
   break  # Stop the loop in case of an error
```

{% endstep %}

{% step %}

### Load data into a GeoPandas DataFrame

```python
# Extract the geometries and attributes for each feature
geometry = [shape(feature["geometry"]) for feature in all_features]
attributes = [feature["properties"] for feature in all_features]

# Create a GeoDataFrame from the geometries and attributes
gdf = gpd.GeoDataFrame(attributes, geometry=geometry)

# Set the CRS of the GeoDataFrame to EPSG:3857 (Web Mercator)
gdf.set_crs("EPSG:3857", inplace=True)
```

{% endstep %}

{% step %}

### Plot Data

```python
# Plot the features
gdf.plot(figsize=(12,8),facecolor="#2d8fb6", edgecolor="#b19d3e", lw=0.05)
```

<figure><img src="/files/8e274bac294a7ec491f1b0084de61c5259b12a95" alt="An example plot of the wtr-fts-water-2 data covering the Glastonbury Canals.  "><figcaption><p>An example plot of the wtr-fts-water-2 data covering the Glastonbury Canals.</p></figcaption></figure>
{% endstep %}
{% endstepper %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.os.uk/os-apis/accessing-os-apis/os-ngd-api-features/getting-started/libraries/python-geopandas.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
