Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions community/user/ov/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!--fused:pin=1-->
<!--fused:preview-->
<p align="center"><img src="https://fused-magic.s3.us-west-2.amazonaws.com/thumbnails/udfs-staging/Overture_Map_Example2.png" width="600" alt="UDF preview image"></p>

<!--fused:tags-->
Tags: `overture` `coop`

<!--fused:readme-->
Buildings footprints, places of interest (POIs), admin boundaries, and transportation globally from [Overture Maps](https://overturemaps.org/).

## Parameters

- `release`: Overture release ID. Defaults to `2024-12-18-0`. Note that `.` should be replaced with `-` in the ID.
- `type`: One of `infrastructure`, `land`, `land_use`, `water`, `division`, `division_boundary`, `division_area`, `place`, `connector`, `segment`, `address`, `building` (default).
- `theme`: One of `buildings`, `base`, `places`, `transportation`, `divisions`, `addresses`. If not specified, this will be inferred from the type.
- `use_columns`: Load only these columns if specified. Default is to load all columns.

## Run this in any Jupyter Notebook

```python
import fused
import geopandas as gpd

udf = fused.load("https://github.com/fusedio/udfs/tree/main/public/Overture_Maps_Example")
gdf_output = fused.run(udf, x=2622, y=6333, z=14)
gdf = gpd.GeoDataFrame(gdf_output, geometry='geometry', crs='epsg:4326')
gdf.plot()
```
150 changes: 150 additions & 0 deletions community/user/ov/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
{
"version": "0.0.3",
"job_config": {
"version": "0.0.3",
"name": null,
"steps": [
{
"type": "udf",
"udf": {
"type": "geopandas_v2",
"name": "ov",
"entrypoint": "udf",
"parameters": {},
"metadata": {
"fused:defaultParameters": [
{
"parameter": "release",
"value": "",
"type": "string",
"suggestedValues": [
"2024-08-20-0",
"2024-09-18-0",
"2024-10-23-0",
"2024-11-13-0",
"2024-12-18-0",
"2025-01-22-0",
"2025-03-19-1"
]
},
{
"parameter": "theme",
"value": "",
"type": "string",
"suggestedValues": [
"buildings",
"base",
"places",
"transportation",
"addresses",
"divisions"
]
},
{
"parameter": "overture_type",
"value": "",
"type": "string",
"suggestedValues": [
"land_use",
"water",
"place",
"connector",
"segment",
"building",
"address",
"infrastructure",
"land",
"division",
"division_area",
"division_boundary",
"land_cover",
"bathymetry"
]
},
{
"parameter": "use_columns",
"value": [],
"type": "array",
"suggestedValues": [
"geometry",
"id",
"names",
"sources",
"update_time",
"categories"
]
}
],
"fused:vizConfig": {
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 19,
"tileSize": 256,
"pickable": true
},
"rasterLayer": {
"@@type": "BitmapLayer"
},
"vectorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": false,
"pickable": true,
"lineWidthMinPixels": 1,
"getLineColor": {
"@@function": "hasProp",
"property": "r",
"present": "@@=[properties.r, properties.g, properties.b]",
"absent": [
200,
250,
0
]
},
"getFillColor": [
255,
0,
0,
40
]
}
},
"fused:udfType": "vector_tile",
"fused:slug": "ov",
"fused:name": "ov",
"fused:defaultViewState": {
"enable": true,
"latitude": 51.50786698991621,
"longitude": -0.10589130924052784,
"zoom": 13.935948485009598,
"pitch": 0,
"bearing": 0
},
"fused:assetUrl": "https://fused-magic.s3.us-west-2.amazonaws.com/thumbnails/udfs-staging/Overture_Map_Example2.png",
"fused:tags": [
{
"id": "overture",
"label": "overture"
},
{
"id": "coop",
"label": "coop"
}
],
"fused:description": "Buildings footprints, places of interest (POIs), admin boundaries, and transportation globally from [Overture Maps](https://overturemaps.org/).\n\n## Parameters\n\n- `release`: Overture release ID. Defaults to `2024-12-18-0`. Note that `.` should be replaced with `-` in the ID.\n- `type`: One of `infrastructure`, `land`, `land_use`, `water`, `division`, `division_boundary`, `division_area`, `place`, `connector`, `segment`, `address`, `building` (default).\n- `theme`: One of `buildings`, `base`, `places`, `transportation`, `divisions`, `addresses`. If not specified, this will be inferred from the type.\n- `use_columns`: Load only these columns if specified. Default is to load all columns.\n\n## Run this in any Jupyter Notebook\n\n```python\nimport fused\nimport geopandas as gpd\n\nudf = fused.load(\"https://github.com/fusedio/udfs/tree/main/public/Overture_Maps_Example\")\ngdf_output = fused.run(udf, x=2622, y=6333, z=14)\ngdf = gpd.GeoDataFrame(gdf_output, geometry='geometry', crs='epsg:4326')\ngdf.plot()\n```\n",
"fused:explorerPin": "1"
},
"source": "ov.py",
"headers": [
{
"module_name": "utils",
"source_file": "utils.py"
}
]
}
}
],
"metadata": null
}
}
26 changes: 26 additions & 0 deletions community/user/ov/ov.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@fused.udf
def udf(
bounds: fused.types.Bounds = None,
release: str = "2025-03-19-1",
theme: str = None,
overture_type: str = None,
use_columns: list = None,
num_parts: int = None,
min_zoom: int = None,
polygon: str = None,
point_convert: str = None
):
from utils import get_overture

gdf = get_overture(
bounds=bounds,
release=release,
theme=theme,
overture_type=overture_type,
use_columns=use_columns,
num_parts=num_parts,
min_zoom=min_zoom,
polygon=polygon,
point_convert=point_convert
)
return gdf
137 changes: 137 additions & 0 deletions community/user/ov/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
def get_overture(
bounds: fused.types.Bounds = None,
release: str = "2025-03-19-1",
theme: str = None,
overture_type: str = None,
use_columns: list = None,
num_parts: int = None,
min_zoom: int = None,
polygon: str = None,
point_convert: str = None
):
"""Returns Overture data as a GeoDataFrame."""
import logging
import concurrent.futures
import json

import geopandas as gpd
import pandas as pd
from shapely.geometry import shape, box

# Load pinned versions of utility functions.
utils = fused.load("https://github.com/fusedio/udfs/tree/d0e8eb0/public/common/").utils

if release == "2024-02-15-alpha-0":
if overture_type == "administrative_boundary":
overture_type = "administrativeBoundary"
elif overture_type == "land_use":
overture_type = "landUse"
theme_per_type = {
"building": "buildings",
"administrativeBoundary": "admins",
"place": "places",
"landUse": "base",
"water": "base",
"segment": "transportation",
"connector": "transportation",
}
elif release == "2024-03-12-alpha-0":
theme_per_type = {
"building": "buildings",
"administrative_boundary": "admins",
"place": "places",
"land_use": "base",
"water": "base",
"segment": "transportation",
"connector": "transportation",
}
else:
theme_per_type = {
"address": "addresses",
"building": "buildings",
"infrastructure": "base",
"land": "base",
"land_use": "base",
"land_cover": "base",
"water": "base",
"bathymetry": "base",
"place": "places",
"division": "divisions",
"division_area": "divisions",
"division_boundary": "divisions",
"segment": "transportation",
"connector": "transportation",
}

if theme is None:
theme = theme_per_type.get(overture_type, "buildings")

if overture_type is None:
type_per_theme = {v: k for k, v in theme_per_type.items()}
overture_type = type_per_theme[theme]

if num_parts is None:
if overture_type == "building":
if release >= "2025-01-22-0":
num_parts = 6
else:
num_parts = 5
else:
num_parts = 1

if min_zoom is None:
if theme == "admins" or theme == "divisions":
min_zoom = 7
elif theme == "base":
min_zoom = 9
else:
min_zoom = 12

table_path = f"s3://us-west-2.opendata.source.coop/fused/overture/{release}/theme={theme}/type={overture_type}"
table_path = table_path.rstrip("/")

if polygon is not None:
polygon=gpd.GeoDataFrame.from_features(json.loads(polygon))
tile = polygon.geometry.bounds
tile = gpd.GeoDataFrame(
{
"geometry": [
box(
bounds[0],
bounds[1],
bounds[2],
bounds[3],
)
]
}
)

def get_part(part):
part_path = f"{table_path}/part={part}/" if num_parts != 1 else table_path
try:
return utils.table_to_tile(
bounds, table=part_path, use_columns=use_columns, min_zoom=min_zoom
)
except ValueError:
return None

if num_parts > 1:
with concurrent.futures.ThreadPoolExecutor(max_workers=num_parts) as pool:
dfs = list(pool.map(get_part, range(num_parts)))
else:
# Don't bother creating a thread pool to do one thing
dfs = [get_part(0)]

dfs = [df for df in dfs if df is not None]

if len(dfs):
gdf = pd.concat(dfs)

else:
logging.warn("Failed to get any data")
return None

if point_convert is not None:
gdf["geometry"] = gdf.geometry.centroid

return gdf