Copilot commented on code in PR #2905:
URL: https://github.com/apache/sedona/pull/2905#discussion_r3193374832
##########
docs/usecases/04-flood-snapshot.ipynb:
##########
@@ -0,0 +1,410 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "<!--\n",
+ " Licensed to the Apache Software Foundation (ASF) under one\n",
+ " or more contributor license agreements. See the NOTICE file\n",
+ " distributed with this work for additional information\n",
+ " regarding copyright ownership. The ASF licenses this file\n",
+ " to you under the Apache License, Version 2.0 (the\n",
+ " \"License\"); you may not use this file except in compliance\n",
+ " with the License. You may obtain a copy of the License at\n",
+ "\n",
+ " http://www.apache.org/licenses/LICENSE-2.0\n",
+ "\n",
+ " Unless required by applicable law or agreed to in writing,\n",
+ " software distributed under the License is distributed on an\n",
+ " \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+ " KIND, either express or implied. See the License for the\n",
+ " specific language governing permissions and limitations\n",
+ " under the License.\n",
+ "-->\n",
+ "\n",
+ "# Buildings inside a flood extent — and which are critical
infrastructure\n",
+ "\n",
+ "An end-to-end disaster-response workflow. We answer:\n",
+ "\n",
+ "> **A flood happened over this AOI. Which buildings are inside the flood
extent, and how many of them are hospitals, schools, or fire stations?**\n",
+ "\n",
+ "**Pipeline:**\n",
+ "1. Synthesize a Sentinel-1-VV-style backscatter raster (low values where
water sits flat — that's the flood signature SAR sees).\n",
+ "2. Threshold with `RS_MapAlgebra` → binary water mask raster.\n",
+ "3. Vectorize the mask: `RS_PixelAsPolygons` + `explode` + filter +
`ST_Union_Agg` → a single dissolved flood polygon.\n",
+ "4. `ST_Buffer` slightly to absorb SAR speckle.\n",
+ "5. Synthesize building footprints labelled with infrastructure type
(`residential` / `hospital` / `school` / `fire_station`).\n",
+ "6. `ST_Intersects` spatial join to find affected buildings; flag any
whose `type != 'residential'` as critical.\n",
+ "7. Write the affected-buildings table as **GeoParquet 1.1** (auto
covering-bbox + projjson CRS), read back, plot.\n",
+ "\n",
+ "All inputs are synthesized in the notebook so it runs offline. To replace
the synthesis cell with real Sentinel-1 imagery in production, point Sedona's
[STAC reader](../tutorial/files/stac-sedona-spark.md) at an `earth-search`
collection and feed the chosen scene's VV-polarization asset URL into the same
`sedona.read.format(\"raster\")` call below.\n",
+ "\n",
+ "**Requires Sedona ≥ 1.9.0** for the auto-tiling raster reader (GH-2672)
and the GeoParquet 1.1 writer's auto-populated covering-bbox + projjson CRS
metadata (GH-2646, GH-2664)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 1. Connect to Spark through SedonaContext"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sedona.spark import SedonaContext\n",
+ "\n",
+ "config =
SedonaContext.builder().master(\"spark://localhost:7077\").getOrCreate()\n",
+ "sedona = SedonaContext.create(config)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 2. Synthesize a Sentinel-1-VV-style backscatter raster\n",
+ "\n",
+ "Sentinel-1 SAR over flat water returns very low backscatter (water
specularly reflects radar away from the satellite); over land the surface
scatters energy back. We simulate that contrast with a single-band `float32`
raster: high values everywhere except a circular flood patch in the south-west
quadrant which we drop to low values. Written as a tiled GeoTIFF so the Sedona
raster reader accepts it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "\n",
+ "import numpy as np\n",
+ "import rasterio\n",
+ "from rasterio.transform import from_bounds\n",
+ "\n",
+ "WORK = \"/tmp/flood-snapshot\"\n",
+ "os.makedirs(WORK, exist_ok=True)\n",
+ "\n",
+ "AOI = (-91.10, 41.50, -91.00, 41.60)\n",
+ "W = H = 128\n",
+ "transform = from_bounds(*AOI, W, H)\n",
+ "rng = np.random.default_rng(11)\n",
+ "\n",
+ "ys, xs = np.mgrid[0:H, 0:W]\n",
+ "flood_mask = ((xs - 32) ** 2 + (ys - 96) ** 2) < 28**2 # circle in SW
corner\n",
+ "backscatter = 0.5 + 0.05 * rng.standard_normal((H, W)) # land\n",
+ "backscatter = np.where(\n",
+ " flood_mask, 0.05 + 0.02 * rng.standard_normal((H, W)), backscatter\n",
+ ")\n",
+ "backscatter = backscatter.clip(0, 1).astype(\"float32\")\n",
+ "\n",
+ "scene_path = f\"{WORK}/sentinel1_vv.tif\"\n",
+ "with rasterio.open(\n",
+ " scene_path,\n",
+ " \"w\",\n",
+ " driver=\"GTiff\",\n",
+ " tiled=True,\n",
+ " blockxsize=128,\n",
+ " blockysize=128,\n",
+ " height=H,\n",
+ " width=W,\n",
+ " count=1,\n",
+ " dtype=\"float32\",\n",
+ " crs=\"EPSG:4326\",\n",
+ " transform=transform,\n",
+ ") as dst:\n",
+ " dst.write(backscatter, 1)\n",
+ " dst.set_band_description(1, \"vv\")\n",
+ "\n",
+ "print(\n",
+ " f\"backscatter min={backscatter.min():.2f}
max={backscatter.max():.2f} \"\n",
+ " f\"flood pixels={int(flood_mask.sum())}/{H*W}\"\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 3. Threshold the backscatter into a water-mask raster\n",
+ "\n",
+ "Single-raster `RS_MapAlgebra` with a comparison expression: every pixel
whose VV backscatter is below `0.2` becomes 1 (water), every other pixel
becomes 0 (dry). The result is a `uint8` mask raster the same size and CRS as
the input."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "scene = sedona.read.format(\"raster\").load(scene_path)\n",
+ "scene.createOrReplaceTempView(\"scene\")\n",
+ "\n",
+ "mask = sedona.sql(\"\"\"\n",
+ " SELECT x, y,\n",
+ " RS_MapAlgebra(\n",
+ " rast, 'B',\n",
+ " 'out[0] = rast[0] < 0.2 ? 1 : 0;'\n",
+ " ) AS rast\n",
+ " FROM scene\n",
+ "\"\"\")\n",
+ "mask.cache()\n",
+ "mask.createOrReplaceTempView(\"mask\")\n",
+ "mask.selectExpr(\n",
+ " \"x\",\n",
+ " \"y\",\n",
+ " \"RS_BandPixelType(rast, 1) as dtype\",\n",
+ " \"RS_Width(rast) as w\",\n",
+ " \"RS_Height(rast) as h\",\n",
+ ").show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 4. Vectorize the mask into a single dissolved flood polygon\n",
+ "\n",
+ "`RS_PixelAsPolygons(raster, band)` returns an array of `{geom, val, x,
y}` structs — one per pixel. We `explode` that into rows, keep only the wet
pixels (`val = 1`), and dissolve them into a single `MultiPolygon` via
`ST_Union_Agg`. A small `ST_Buffer` (0.0005°, ~50 m) absorbs SAR speckle along
the edge of the flood."
Review Comment:
Section 4 markdown documents `RS_PixelAsPolygons` structs as having a `val`
field and shows filtering on `val = 1`, but the notebook code uses
`pixel.value` (and the PR description notes the field is `value`). Please
update the markdown to match the actual struct field name (`value`) so readers
don’t copy the wrong column name.
##########
docs/usecases/04-flood-snapshot.ipynb:
##########
@@ -0,0 +1,410 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "<!--\n",
+ " Licensed to the Apache Software Foundation (ASF) under one\n",
+ " or more contributor license agreements. See the NOTICE file\n",
+ " distributed with this work for additional information\n",
+ " regarding copyright ownership. The ASF licenses this file\n",
+ " to you under the Apache License, Version 2.0 (the\n",
+ " \"License\"); you may not use this file except in compliance\n",
+ " with the License. You may obtain a copy of the License at\n",
+ "\n",
+ " http://www.apache.org/licenses/LICENSE-2.0\n",
+ "\n",
+ " Unless required by applicable law or agreed to in writing,\n",
+ " software distributed under the License is distributed on an\n",
+ " \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+ " KIND, either express or implied. See the License for the\n",
+ " specific language governing permissions and limitations\n",
+ " under the License.\n",
+ "-->\n",
+ "\n",
+ "# Buildings inside a flood extent — and which are critical
infrastructure\n",
+ "\n",
+ "An end-to-end disaster-response workflow. We answer:\n",
+ "\n",
+ "> **A flood happened over this AOI. Which buildings are inside the flood
extent, and how many of them are hospitals, schools, or fire stations?**\n",
+ "\n",
+ "**Pipeline:**\n",
+ "1. Synthesize a Sentinel-1-VV-style backscatter raster (low values where
water sits flat — that's the flood signature SAR sees).\n",
+ "2. Threshold with `RS_MapAlgebra` → binary water mask raster.\n",
+ "3. Vectorize the mask: `RS_PixelAsPolygons` + `explode` + filter +
`ST_Union_Agg` → a single dissolved flood polygon.\n",
+ "4. `ST_Buffer` slightly to absorb SAR speckle.\n",
+ "5. Synthesize building footprints labelled with infrastructure type
(`residential` / `hospital` / `school` / `fire_station`).\n",
+ "6. `ST_Intersects` spatial join to find affected buildings; flag any
whose `type != 'residential'` as critical.\n",
Review Comment:
In the pipeline overview, step 6 says to flag critical infrastructure via
`type != 'residential'`, but the actual query flags critical with an explicit
IN list (`hospital`, `school`, `fire_station`). To avoid confusing readers (and
to stay correct if additional non-residential types are added later), update
the markdown to match the implemented condition.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]