From 78cb8a7abf016ccfad31774436fc7fcdaa74871a Mon Sep 17 00:00:00 2001 From: Qiusheng Wu Date: Wed, 4 Dec 2024 12:32:43 -0500 Subject: [PATCH] Add Fused notebook example (#1014) * Add Fused notebook example * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix typos * Update notebook headings * Fix typos * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/notebooks/102_fused.ipynb | 368 +++++++++++++++++++++++++++++++++ mkdocs.yml | 2 + 2 files changed, 370 insertions(+) create mode 100644 docs/notebooks/102_fused.ipynb diff --git a/docs/notebooks/102_fused.ipynb b/docs/notebooks/102_fused.ipynb new file mode 100644 index 0000000000..5888ad587a --- /dev/null +++ b/docs/notebooks/102_fused.ipynb @@ -0,0 +1,368 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "[![image](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://demo.leafmap.org/lab/index.html?path=notebooks/102_fused.ipynb)\n", + "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/leafmap/blob/master/docs/notebooks/102_fused.ipynb)\n", + "[![image](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/opengeos/leafmap/HEAD)\n", + "\n", + "**Mapping Overture Buildings and Foursquare Places with Leafmap + Fused**\n", + "\n", + "Fetch data by calling [Fused UDFs](https://docs.fused.io/core-concepts/write/) and render it on a [Leafmap](https://leafmap.org/) map.\n", + "\n", + "This notebook shows how you can:\n", + "\n", + "1. Load [Overture Buildings](https://docs.overturemaps.org/getting-data/fused) for a drawn area\n", + "2. Load [Foursquare (FSQ) Place](https://docs.foursquare.com/data-products/docs/access-fsq-os-places) POIs for a drawn area" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install fused>=1.11.1 \"leafmap[maplibre]\" -q" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pandas as pd\n", + "import geopandas as gpd\n", + "from shapely.geometry import shape\n", + "import fused\n", + "import leafmap\n", + "import leafmap.maplibregl as maplibre" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "## 1. Load Overture Buildings for drawn area\n", + "\n", + "First draw a bounding box over an area of interest (AOI) and create a GeoDataFrame with it. Then, [run the Overture UDF](https://docs.fused.io/core-concepts/run/) to fetch data for that AOI.\n", + "\n", + "### 1.1 First, draw an AOI" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40.713370, -73.996181], zoom=14)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": {}, + "outputs": [], + "source": [ + "# If no AOI is drawn, use the default AOI\n", + "\n", + "if m.user_roi is None:\n", + " m.user_roi = {\n", + " \"type\": \"Feature\",\n", + " \"properties\": {},\n", + " \"geometry\": {\n", + " \"type\": \"Polygon\",\n", + " \"coordinates\": [\n", + " [\n", + " [-74.025621, 40.699967],\n", + " [-74.025621, 40.730283],\n", + " [-73.966055, 40.730283],\n", + " [-73.966055, 40.699967],\n", + " [-74.025621, 40.699967],\n", + " ]\n", + " ],\n", + " },\n", + " }" + ] + }, + { + "cell_type": "markdown", + "id": "6", + "metadata": {}, + "source": [ + "### 1.2 Then, convert it to a GeoDataFrame." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7", + "metadata": {}, + "outputs": [], + "source": [ + "import geopandas as gpd\n", + "\n", + "# Convert drawing to GeoDataFrame\n", + "gdf_drawing = gpd.GeoDataFrame(\n", + " [m.user_roi[\"properties\"]], geometry=[shape(m.user_roi[\"geometry\"])]\n", + ")\n", + "\n", + "gdf_drawing" + ] + }, + { + "cell_type": "markdown", + "id": "8", + "metadata": {}, + "source": [ + "### 1.3 Fetch Overture Buildings for the AOI and render them on the map\n", + "\n", + "The data comes from calling the \"[Overture Maps Example](https://www.fused.io/workbench/catalog/Overture_Maps_Example-64071fb8-2c96-4015-adb9-596c3bac6787)\" public UDF with `fused.run`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9", + "metadata": {}, + "outputs": [], + "source": [ + "# Fetch Overture Buildings GDF with Fused UDF\n", + "gdf = fused.run(\"UDF_Overture_Maps_Example\", bbox=gdf_drawing)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "gdf.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11", + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"The number of buildings within the AOI: {len(gdf)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "# Add GDF to map\n", + "m.add_gdf(\n", + " gdf[[\"id\", \"geometry\", \"height\", \"class\"]],\n", + " layer_type=\"fill\",\n", + " name=\"Buildings\",\n", + " fill_colors=[\"red\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "### 1.4 Visualize buildings in 3D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "m = maplibre.Map(pitch=60)\n", + "m.add_basemap(\"USGS.USImagery\")\n", + "gdf_filter = gdf[gdf.height > 0][[\"id\", \"geometry\", \"height\", \"class\"]]\n", + "m.add_data(gdf_filter, column=\"height\", cmap=\"Blues\", extrude=True, name=\"Buildings\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "m.layer_interact()" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, + "source": [ + "## 2. Load FSQ Places POIs for drawn area\n", + "\n", + "### 2.1 Fetch FSQ Places for the AOI (defined above) and render them on the map\n", + "\n", + "The data comes from calling the \"[Foursquare Open Source Places](https://www.fused.io/workbench/catalog/Foursquare_Open_Source_Places-5cd75ead-e319-4279-8efc-04276de145bc)\" public UDF with `fused.run`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17", + "metadata": {}, + "outputs": [], + "source": [ + "# Fetch FSQ GDF with Fused UDF\n", + "gdf = fused.run(\"UDF_Foursquare_Open_Source_Places\", bbox=gdf_drawing)\n", + "\n", + "# `add_points_from_xy` requires latitude and longitude columns\n", + "gdf[\"latitude\"] = gdf.geometry.y\n", + "gdf[\"longitude\"] = gdf.geometry.x\n", + "\n", + "# Show place categories\n", + "set(gdf.level1_category_name.values)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "# Subsample the gdf\n", + "gdf_sample = (\n", + " gdf[[\"name\", \"latitude\", \"longitude\", \"geometry\"]].head(200).reset_index(drop=True)\n", + ")\n", + "# gdf_sample = gdf[gdf.level1_category_name == 'Dining and Drinking'][['name', 'latitude', 'longitude']].head(1000).reset_index(drop=True)\n", + "gdf_sample" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "### 2.2 Visualize the POIs on a 2d map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40.713370, -73.996181], zoom=14)\n", + "# Add as marker cluster\n", + "m.add_points_from_xy(\n", + " gdf_sample,\n", + " x=\"longitude\",\n", + " y=\"latitude\",\n", + " spin=False,\n", + " add_legend=True,\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "21", + "metadata": {}, + "source": [ + "### 2.3 Visualize POIs with OpenStreetMap vector tiles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22", + "metadata": {}, + "outputs": [], + "source": [ + "m = maplibre.Map(pitch=60, style=\"https://maps.gishub.org/styles/openstreetmap.json\")\n", + "m.add_gdf(gdf_sample, name=\"Places\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "### 2.4 Visualize the POIs on a 3D map with Overture buildings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24", + "metadata": {}, + "outputs": [], + "source": [ + "m = maplibre.Map(zoom=18, pitch=60, style=\"positron\")\n", + "m.add_overture_3d_buildings()\n", + "m.add_gdf(gdf_sample, name=\"Places\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "25", + "metadata": {}, + "source": [ + "### 2.5 Visualize the POIs on a 3D map with [OpenFreeMap](https://openfreemap.org/) vector tiles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26", + "metadata": {}, + "outputs": [], + "source": [ + "m = maplibre.Map(pitch=60, style=\"liberty\")\n", + "m.add_gdf(gdf_sample, name=\"Places\")\n", + "m" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/mkdocs.yml b/mkdocs.yml index 2d04613a23..1a6976bf4f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -81,6 +81,7 @@ plugins: "notebooks/94_mapbox.ipynb", "notebooks/99_wetlands.ipynb", "notebooks/101_nasa_opera.ipynb", + "notebooks/102_fused.ipynb", ] markdown_extensions: @@ -337,3 +338,4 @@ nav: - notebooks/99_wetlands.ipynb - notebooks/100_nlcd.ipynb - notebooks/101_nasa_opera.ipynb + - notebooks/102_fused.ipynb