{
"cells": [
{
"cell_type": "markdown",
"id": "374aa2b1",
"metadata": {},
"source": [
"# Assessing Overlap in NISAR and ESA BIOMASS Datasets\n",
"\n",
"Date: February 4, 2026\n",
"\n",
"Authors: Harshini Girish (UAH), Rajat Shinde (UAH), Alex Mandel (Development Seed), Samantha Niemoeller (JPL)\n",
"\n",
"Description: This notebook queries NISAR L2 GCOV granules (via `earthaccess`) and ESA BIOMASS satellite items (via the ESA MAAP STAC API, e.g., `BiomassLevel1b`) for a chosen AOI and time settings. It converts returned items to footprint polygons and plots them on a single interactive Folium map as two toggleable layers. An optional overlap layer highlights where NISAR and BIOMASS footprints intersect (bbox-only or true geometry). The result quickly shows where data coincides spatially to support fusion workflows.\n"
]
},
{
"cell_type": "markdown",
"id": "93b44b7d-f5a5-4048-80e5-737db0998a43",
"metadata": {},
"source": [
"## Run This Notebook\n",
"\n",
"To access and run this tutorial within MAAP's Algorithm Development Environment (ADE), please refer to the [\"Getting started with the MAAP\"](https://docs.maap-project.org/en/latest/getting_started/getting_started.html) section of our documentation.\n",
"\n",
"Disclaimer: it is highly recommended to run a tutorial within MAAP's ADE, which already includes packages specific to MAAP, such as maap-py. Running the tutorial outside of the MAAP ADE may lead to errors. Additionally, it is recommended to use the `Pangeo` workspace within the ADE, since certain packages relevant to this tutorial are already installed."
]
},
{
"cell_type": "markdown",
"id": "399aa805-c518-4cde-812d-8729c5e888d9",
"metadata": {},
"source": [
"## Additional Resources\n",
"- [NISAR](https://nisar.jpl.nasa.gov/)\n",
"- [BIOMASS](https://docs.maap-project.org/en/develop/science/ESA_CCI/ESA_CCI_V5_Token_Access.html)\n"
]
},
{
"cell_type": "markdown",
"id": "a328ae66-198a-4906-b2f5-ffc387ee44b1",
"metadata": {},
"source": [
"## Import and Install Packages"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "86047982",
"metadata": {},
"outputs": [],
"source": [
"import pystac_client\n",
"import geopandas as gpd\n",
"import pandas as pd\n",
"import folium\n",
"from folium import GeoJson\n"
]
},
{
"cell_type": "markdown",
"id": "80529155",
"metadata": {},
"source": [
"## Inputs\n",
"\n",
"This section defines the parameters used throughout the notebook to search both catalogs and compute overlaps.\n",
"\n",
"- **BBOX** defines the area of interest as **(min_lon, min_lat, max_lon, max_lon)** and can be used to spatially filter both datasets. \n",
"- **NISAR_DT** sets the datetime range for the NISAR STAC search (tighten this first to avoid timeouts). \n",
"- **BIOMASS_DT** sets the datetime range for the BIOMASS STAC search. \n",
"- **NISAR_STAC_URL** is the STAC endpoint used to query NISAR items (CMR-STAC / ASF). \n",
"- **NISAR_COLLECTION** is the NISAR collection ID used in the STAC search (e.g., `NISAR_L2_GSLC_BETA_V1_1`). \n",
"- **BIOMASS_STAC_URL** is the STAC endpoint used to query BIOMASS items (ESA MAAP STAC). \n",
"- **BIOMASS_COLLECTION** is the BIOMASS collection name used in the STAC search (e.g., `BiomassLevel1b`).\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "8ed53932-c0b5-4223-ba86-aed95cbd65d3",
"metadata": {},
"outputs": [],
"source": [
"# Common query parameters (edit to your AOI/time window)\n",
"BBOX = [-180, -90, 180, 90] # [minx, miny, maxx, maxy]\n",
"NISAR_DT = \"2025-10-01/2025-12-31\" # tighten first to avoid timeouts\n",
"BIOMASS_DT = \"2024-01-01/..\" # adjust if needed\n",
"\n",
"NISAR_STAC_URL = \"https://cmr.earthdata.nasa.gov/stac/ASF\"\n",
"NISAR_COLLECTION = \"NISAR_L2_GSLC_BETA_V1_1\"\n",
"\n",
"BIOMASS_STAC_URL = \"https://catalog.maap.eo.esa.int/catalogue/\"\n",
"BIOMASS_COLLECTION = \"BiomassLevel1b\"\n"
]
},
{
"cell_type": "markdown",
"id": "e2dc36db-f686-41e7-8cbf-c152fcbf84fc",
"metadata": {},
"source": [
"## Query STAC and Convert Items to a GeoDataFrame\n"
]
},
{
"cell_type": "markdown",
"id": "5b6c52d4",
"metadata": {},
"source": [
"### 1) NISAR data"
]
},
{
"cell_type": "markdown",
"id": "9a8b1506-d6a1-422b-984c-92e172e298b7",
"metadata": {},
"source": [
"This section connects to the CMR/ASF STAC API and runs a STAC search for NISAR items using the same spatial/temporal filters used in the notebook (bbox and datetime). The returned STAC Items are converted into `gdf_nisar`, a GeoDataFrame whose `geometry` column contains the true NISAR footprint polygons and whose ID/title field is kept for labeling and later joins—no data files are downloaded, only metadata footprints are used."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "b2471531-9cc0-4e91-a065-ee2c2a0ba6fd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"NISAR items returned: 6\n"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" nisar_id | \n",
" geometry | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" NISAR_L2_PR_GSLC_003_005_D_077_4005_DHDH_A_202... | \n",
" POLYGON ((77.30164 24.17615, 76.70841 22.04128... | \n",
"
\n",
" \n",
" | 1 | \n",
" NISAR_L2_PR_GSLC_003_064_D_130_7700_SHNA_A_202... | \n",
" POLYGON ((-2.61271 -81.76059, -6.78497 -82.596... | \n",
"
\n",
" \n",
" | 2 | \n",
" NISAR_L2_PR_GSLC_004_064_D_130_7700_SHNA_A_202... | \n",
" POLYGON ((-2.70717 -81.78256, -6.90256 -82.617... | \n",
"
\n",
" \n",
" | 3 | \n",
" NISAR_L2_PR_GSLC_004_076_A_022_2005_QPDH_A_202... | \n",
" POLYGON ((-88.24687 39.87043, -89.11556 41.970... | \n",
"
\n",
" \n",
" | 4 | \n",
" NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... | \n",
" POLYGON ((42.96535 12.02728, 42.46821 14.11353... | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" nisar_id \\\n",
"0 NISAR_L2_PR_GSLC_003_005_D_077_4005_DHDH_A_202... \n",
"1 NISAR_L2_PR_GSLC_003_064_D_130_7700_SHNA_A_202... \n",
"2 NISAR_L2_PR_GSLC_004_064_D_130_7700_SHNA_A_202... \n",
"3 NISAR_L2_PR_GSLC_004_076_A_022_2005_QPDH_A_202... \n",
"4 NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... \n",
"\n",
" geometry \n",
"0 POLYGON ((77.30164 24.17615, 76.70841 22.04128... \n",
"1 POLYGON ((-2.61271 -81.76059, -6.78497 -82.596... \n",
"2 POLYGON ((-2.70717 -81.78256, -6.90256 -82.617... \n",
"3 POLYGON ((-88.24687 39.87043, -89.11556 41.970... \n",
"4 POLYGON ((42.96535 12.02728, 42.46821 14.11353... "
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nisar_catalog = pystac_client.Client.open(NISAR_STAC_URL)\n",
"\n",
"nisar_search = nisar_catalog.search(\n",
" collections=[NISAR_COLLECTION],\n",
" bbox=BBOX,\n",
" datetime=NISAR_DT,\n",
" max_items=500,\n",
")\n",
"nisar_items = list(nisar_search.items())\n",
"print(\"NISAR items returned:\", len(nisar_items))\n",
"\n",
"# Convert STAC Items → GeoDataFrame\n",
"nisar_features = []\n",
"for it in nisar_items:\n",
" \n",
" nisar_features.append({\n",
" \"type\": \"Feature\",\n",
" \"geometry\": it.geometry,\n",
" \"properties\": {\n",
" \"nisar_id\": it.id,\n",
" **(it.properties or {}),\n",
" },\n",
" })\n",
"\n",
"gdf_nisar = gpd.GeoDataFrame.from_features(nisar_features, crs=\"EPSG:4326\")\n",
"gdf_nisar = gdf_nisar[[\"nisar_id\", \"geometry\"]]\n",
"gdf_nisar.head()\n"
]
},
{
"cell_type": "markdown",
"id": "e94fa9b5",
"metadata": {},
"source": [
"### 2) ESA BIOMASS \n",
"\n",
"This part connects to the ESA MAAP STAC endpoint `(https://catalog.maap.eo.esa.int/catalogue/)` and searches the `BiomassLevel1b` collection using the notebook’s time range and optional `bbox` filter. The returned BIOMASS STAC Items are converted into gdf_biomass with polygon geometries preserved and a stable id/title column added for display and matching—again, this is footprint metadata only, not raster access."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "8c979f77",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"BIOMASS items returned: 2000\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" biomass_id | \n",
" start_datetime | \n",
" end_datetime | \n",
" datetime | \n",
" geometry | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" BIO_S2_DGM__1S_20251212T011542_20251212T011603... | \n",
" 2025-12-12T01:15:42.413Z | \n",
" 2025-12-12T01:16:03.140Z | \n",
" 2025-12-12T01:15:42.413Z | \n",
" POLYGON ((-133.8954 -76.78645, -131.65558 -77.... | \n",
"
\n",
" \n",
" | 1 | \n",
" BIO_S2_DGM__1S_20251212T011407_20251212T011427... | \n",
" 2025-12-12T01:14:07.171Z | \n",
" 2025-12-12T01:14:27.898Z | \n",
" 2025-12-12T01:14:07.171Z | \n",
" POLYGON ((-125.59866 -71.44219, -123.89382 -71... | \n",
"
\n",
" \n",
" | 2 | \n",
" BIO_S2_DGM__1S_20251212T015732_20251212T015753... | \n",
" 2025-12-12T01:57:32.641Z | \n",
" 2025-12-12T01:57:53.290Z | \n",
" 2025-12-12T01:57:32.641Z | \n",
" POLYGON ((46.75876 49.9374, 45.91077 49.75396,... | \n",
"
\n",
" \n",
" | 3 | \n",
" BIO_S2_DGM__1S_20251212T015538_20251212T015559... | \n",
" 2025-12-12T01:55:38.817Z | \n",
" 2025-12-12T01:55:59.469Z | \n",
" 2025-12-12T01:55:38.817Z | \n",
" POLYGON ((49.76923 43.18403, 49.01818 43.01984... | \n",
"
\n",
" \n",
" | 4 | \n",
" BIO_S2_DGM__1S_20251212T015500_20251212T015521... | \n",
" 2025-12-12T01:55:00.871Z | \n",
" 2025-12-12T01:55:21.523Z | \n",
" 2025-12-12T01:55:00.871Z | \n",
" POLYGON ((50.63847 40.91793, 49.91332 40.7588,... | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" biomass_id \\\n",
"0 BIO_S2_DGM__1S_20251212T011542_20251212T011603... \n",
"1 BIO_S2_DGM__1S_20251212T011407_20251212T011427... \n",
"2 BIO_S2_DGM__1S_20251212T015732_20251212T015753... \n",
"3 BIO_S2_DGM__1S_20251212T015538_20251212T015559... \n",
"4 BIO_S2_DGM__1S_20251212T015500_20251212T015521... \n",
"\n",
" start_datetime end_datetime \\\n",
"0 2025-12-12T01:15:42.413Z 2025-12-12T01:16:03.140Z \n",
"1 2025-12-12T01:14:07.171Z 2025-12-12T01:14:27.898Z \n",
"2 2025-12-12T01:57:32.641Z 2025-12-12T01:57:53.290Z \n",
"3 2025-12-12T01:55:38.817Z 2025-12-12T01:55:59.469Z \n",
"4 2025-12-12T01:55:00.871Z 2025-12-12T01:55:21.523Z \n",
"\n",
" datetime geometry \n",
"0 2025-12-12T01:15:42.413Z POLYGON ((-133.8954 -76.78645, -131.65558 -77.... \n",
"1 2025-12-12T01:14:07.171Z POLYGON ((-125.59866 -71.44219, -123.89382 -71... \n",
"2 2025-12-12T01:57:32.641Z POLYGON ((46.75876 49.9374, 45.91077 49.75396,... \n",
"3 2025-12-12T01:55:38.817Z POLYGON ((49.76923 43.18403, 49.01818 43.01984... \n",
"4 2025-12-12T01:55:00.871Z POLYGON ((50.63847 40.91793, 49.91332 40.7588,... "
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"biomass_catalog = pystac_client.Client.open(BIOMASS_STAC_URL)\n",
"\n",
"biomass_search = biomass_catalog.search(\n",
" collections=[BIOMASS_COLLECTION],\n",
" bbox=BBOX,\n",
" datetime=BIOMASS_DT,\n",
" max_items=2000,\n",
" method=\"GET\",\n",
")\n",
"\n",
"biomass_items = list(biomass_search.items())\n",
"print(\"BIOMASS items returned:\", len(biomass_items))\n",
"\n",
"biomass_features = []\n",
"for it in biomass_items:\n",
" if it.geometry is None:\n",
" raise ValueError(f\"Item {it.id} has no geometry (footprint).\")\n",
" props = it.properties or {}\n",
" biomass_features.append({\n",
" \"type\": \"Feature\",\n",
" \"geometry\": it.geometry,\n",
" \"properties\": {\n",
" \"biomass_id\": it.id,\n",
" \"start_datetime\": props.get(\"start_datetime\"),\n",
" \"end_datetime\": props.get(\"end_datetime\"),\n",
" \"datetime\": props.get(\"datetime\"),\n",
" },\n",
" })\n",
"\n",
"gdf_biomass = gpd.GeoDataFrame.from_features(biomass_features, crs=\"EPSG:4326\")\n",
"gdf_biomass = gdf_biomass[[\"biomass_id\", \"start_datetime\", \"end_datetime\", \"datetime\", \"geometry\"]]\n",
"gdf_biomass.head()\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "729cd4a4",
"metadata": {},
"source": [
"## Interactive map: NISAR and BIOMASS footprint layers\n",
"\n",
"Here the notebook creates an interactive Folium map and overlays the two GeoDataFrames using distinct styles (e.g., NISAR in blue and BIOMASS in orange) so you can visually compare coverage. Tooltips show the granule/item identifiers when you hover, and a layer control lets you toggle the layers, which makes it easy to confirm the footprints are in the right places before doing any intersection."
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "9852af86-0bcc-4913-ab36-323c18069f77",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"Make this Notebook Trusted to load map: File -> Trust Notebook
"
],
"text/plain": [
""
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## Ensure both are WGS84 for folium\n",
"gdf_nisar = gdf_nisar.to_crs(\"EPSG:4326\")\n",
"gdf_biomass = gdf_biomass.to_crs(\"EPSG:4326\")\n",
"\n",
"# Center/zoom using combined bounds\n",
"combined = gpd.GeoSeries(list(gdf_nisar.geometry) + list(gdf_biomass.geometry), crs=\"EPSG:4326\")\n",
"minx, miny, maxx, maxy = combined.total_bounds\n",
"center = [(miny + maxy) / 2, (minx + maxx) / 2]\n",
"\n",
"m = folium.Map(location=center, tiles=\"OpenStreetMap\", zoom_start=3)\n",
"\n",
"def style_nisar(_):\n",
" return {\"color\": \"#1f77b4\", \"weight\": 2, \"fillOpacity\": 0.15} # blue\n",
"\n",
"def style_biomass(_):\n",
" return {\"color\": \"#ff7f0e\", \"weight\": 1, \"fillOpacity\": 0.10} # orange\n",
"\n",
"GeoJson(\n",
" gdf_nisar.__geo_interface__,\n",
" name=f\"NISAR ({len(gdf_nisar)})\",\n",
" tooltip=folium.GeoJsonTooltip(fields=[\"nisar_id\"]),\n",
" style_function=style_nisar,\n",
").add_to(m)\n",
"\n",
"GeoJson(\n",
" gdf_biomass.__geo_interface__,\n",
" name=f\"BIOMASS ({len(gdf_biomass)})\",\n",
" tooltip=folium.GeoJsonTooltip(fields=[\"biomass_id\"]),\n",
" style_function=style_biomass,\n",
").add_to(m)\n",
"\n",
"folium.LayerControl(collapsed=False).add_to(m)\n",
"m.fit_bounds([[miny, minx], [maxy, maxx]])\n",
"m\n"
]
},
{
"cell_type": "markdown",
"id": "2312467f-cdb5-472e-9429-0ddf09af29bf",
"metadata": {},
"source": [
"## Overlap of BIOMASS tiles intersecting with NISAR granules"
]
},
{
"cell_type": "markdown",
"id": "a5b33a76-2f12-4a22-8904-57ccd1e71983",
"metadata": {},
"source": [
"This cell uses GeoPandas spatial join to identify which BIOMASS footprint polygons intersect which NISAR footprint polygons. It runs gpd.sjoin() with `how=\"inner\"` and `predicate=\"intersects\"` on `gdf_nisar` and `gdf_biomass` (after resetting indices for a clean join), producing pairs where each row represents one intersecting NISAR–BIOMASS match. It then prints the total number of intersection pairs found, and builds a compact summary table called matches by keeping only the `nisar_id` and `biomass_id` columns, removing any duplicate pairs, resetting the index, and showing the first 25 results so you can quickly see which specific granules/tiles overlap."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "4d798201-833b-4a56-9109-b1d453534d13",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overlap pairs: 8\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" nisar_id | \n",
" biomass_id | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... | \n",
" BIO_S1_DGM__1S_20251121T153442_20251121T153503... | \n",
"
\n",
" \n",
" | 1 | \n",
" NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... | \n",
" BIO_S2_DGM__1S_20251214T025234_20251214T025254... | \n",
"
\n",
" \n",
" | 2 | \n",
" NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... | \n",
" BIO_S2_DGM__1S_20251217T025236_20251217T025256... | \n",
"
\n",
" \n",
" | 3 | \n",
" NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... | \n",
" BIO_S2_DGM__1S_20251217T025255_20251217T025310... | \n",
"
\n",
" \n",
" | 4 | \n",
" NISAR_L2_PR_GSLC_006_172_A_008_2005_DHDH_A_202... | \n",
" BIO_S1_DGM__1S_20251121T153442_20251121T153503... | \n",
"
\n",
" \n",
" | 5 | \n",
" NISAR_L2_PR_GSLC_006_172_A_008_2005_DHDH_A_202... | \n",
" BIO_S2_DGM__1S_20251214T025234_20251214T025254... | \n",
"
\n",
" \n",
" | 6 | \n",
" NISAR_L2_PR_GSLC_006_172_A_008_2005_DHDH_A_202... | \n",
" BIO_S2_DGM__1S_20251217T025236_20251217T025256... | \n",
"
\n",
" \n",
" | 7 | \n",
" NISAR_L2_PR_GSLC_006_172_A_008_2005_DHDH_A_202... | \n",
" BIO_S2_DGM__1S_20251217T025255_20251217T025310... | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" nisar_id \\\n",
"0 NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... \n",
"1 NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... \n",
"2 NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... \n",
"3 NISAR_L2_PR_GSLC_005_172_A_008_2005_DHDH_A_202... \n",
"4 NISAR_L2_PR_GSLC_006_172_A_008_2005_DHDH_A_202... \n",
"5 NISAR_L2_PR_GSLC_006_172_A_008_2005_DHDH_A_202... \n",
"6 NISAR_L2_PR_GSLC_006_172_A_008_2005_DHDH_A_202... \n",
"7 NISAR_L2_PR_GSLC_006_172_A_008_2005_DHDH_A_202... \n",
"\n",
" biomass_id \n",
"0 BIO_S1_DGM__1S_20251121T153442_20251121T153503... \n",
"1 BIO_S2_DGM__1S_20251214T025234_20251214T025254... \n",
"2 BIO_S2_DGM__1S_20251217T025236_20251217T025256... \n",
"3 BIO_S2_DGM__1S_20251217T025255_20251217T025310... \n",
"4 BIO_S1_DGM__1S_20251121T153442_20251121T153503... \n",
"5 BIO_S2_DGM__1S_20251214T025234_20251214T025254... \n",
"6 BIO_S2_DGM__1S_20251217T025236_20251217T025256... \n",
"7 BIO_S2_DGM__1S_20251217T025255_20251217T025310... "
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Spatial join to find overlapping pairs\n",
"pairs = gpd.sjoin(\n",
" gdf_nisar.reset_index(drop=True),\n",
" gdf_biomass.reset_index(drop=True),\n",
" how=\"inner\",\n",
" predicate=\"intersects\",\n",
")\n",
"\n",
"print(\"Overlap pairs:\", len(pairs))\n",
"\n",
"# Compact table of matches (deduped)\n",
"matches = pairs[[\"nisar_id\", \"biomass_id\"]].drop_duplicates().reset_index(drop=True)\n",
"matches.head(25)\n"
]
},
{
"cell_type": "markdown",
"id": "c383d669-995a-461c-a465-0cc695895c78",
"metadata": {},
"source": [
"This cell creates the actual overlap polygons and then visualizes only those overlaps on a clean map. It first pulls the matching BIOMASS geometries for each join result using pairs`[\"index_right\"]`, wraps them as a GeoSeries aligned to pairs.index, and computes the geometric intersection with the NISAR geometry in each row `(pairs.geometry.intersection(right_geom))`, producing overlap_geom. It then builds a new GeoDataFrame called overlap that keeps just the linked identifiers (nisar_id, biomass_id) plus the intersection geometry, and filters out any empty intersections. For visualization, it creates a fresh Folium map (m_overlap) and adds a single GeoJson layer styled in green with a tooltip showing the two IDs on hover; finally, it automatically zooms the map to the extent of the overlap polygons using `overlap.total_bounds` and `fit_bounds`, so the view centers directly on where overlap occurs without showing the original NISAR/BIOMASS layers."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "5a41cefc-4143-488f-8a3d-d73149ed1991",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"Make this Notebook Trusted to load map: File -> Trust Notebook
"
],
"text/plain": [
""
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"right_geom = gdf_biomass.loc[pairs[\"index_right\"], \"geometry\"].values\n",
"right_geom = gpd.GeoSeries(right_geom, index=pairs.index, crs=\"EPSG:4326\")\n",
"\n",
"overlap_geom = pairs.geometry.intersection(right_geom)\n",
"\n",
"overlap = gpd.GeoDataFrame(\n",
" pairs[[\"nisar_id\", \"biomass_id\"]].copy(),\n",
" geometry=overlap_geom,\n",
" crs=\"EPSG:4326\",\n",
")\n",
"overlap = overlap[~overlap.geometry.is_empty]\n",
"\n",
"# Map: overlap only\n",
"m_overlap = folium.Map(tiles=\"OpenStreetMap\")\n",
"\n",
"def style_overlap(_):\n",
" return {\"color\": \"#2ca02c\", \"weight\": 2, \"fillColor\": \"#2ca02c\", \"fillOpacity\": 0.35}\n",
"\n",
"GeoJson(\n",
" overlap.__geo_interface__,\n",
" name=f\"Overlap ({len(overlap)})\",\n",
" tooltip=folium.GeoJsonTooltip(fields=[\"nisar_id\", \"biomass_id\"]),\n",
" style_function=style_overlap,\n",
").add_to(m_overlap)\n",
"\n",
"if len(overlap) > 0:\n",
" minx, miny, maxx, maxy = overlap.total_bounds\n",
" pad = 0.05 \n",
" m_overlap.fit_bounds([[miny - pad, minx - pad], [maxy + pad, maxx + pad]])\n",
"\n",
"m_overlap"
]
}
],
"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.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}