# 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://app.gitbook.com/s/oEzqrBzRGoJw7nQyLj1W/core-concepts/getting-started-with-an-api-project "mention") for more information.&#x20;
* 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/).&#x20;
{% 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

{% code overflow="wrap" %}

```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
```

{% endcode %}
{% 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)
```

{% endstep %}
{% endstepper %}

<figure><img src="https://170091638-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0pZjHxkAvY7Mn6TqFBMD%2Fuploads%2F9AYJdDXX2I8kXOhmzlnW%2Fwtr-fts-water2_output.png?alt=media&#x26;token=4b5e0535-2fd7-4b51-9796-0a3caefb1976" alt="An example plot of the wtr-fts-water-2 data covering the Glastonbury Canals.  "><figcaption></figcaption></figure>
