{"id":6551,"date":"2026-01-23T14:46:16","date_gmt":"2026-01-23T13:46:16","guid":{"rendered":"https:\/\/revodata.nl\/?p=6551"},"modified":"2026-01-23T15:15:37","modified_gmt":"2026-01-23T14:15:37","slug":"building-a-geospatial-time-machine","status":"publish","type":"post","link":"https:\/\/revodata.nl\/nl\/building-a-geospatial-time-machine\/","title":{"rendered":"Building a Geospatial Time Machine"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"6551\" class=\"elementor elementor-6551\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-52459a6 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"52459a6\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-50b64aa\" data-id=\"50b64aa\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-be25c4f elementor-widget elementor-widget-text-editor\" data-id=\"be25c4f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Editor&#8217;s note: This post was originally published June 12th, 2025.\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f932491 elementor-widget elementor-widget-heading\" data-id=\"f932491\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">What is environmental change detection?\n\n\n<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-462a8a8 elementor-widget elementor-widget-text-editor\" data-id=\"462a8a8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"b76e\" class=\"pw-post-body-paragraph xz ya td yb b yc yd ye yf yg yh yi yj rs yk yl ym rv yn yo yp ry yq yr ys yt go bl\" data-selectable-paragraph=\"\">Think of it as a time machine for planet Earth. No flux capacitor, no DeLorean, and no Marty McFly needed!\ud83d\ude09 Just some cool tech that lets us peek into how our world changes over time.<\/p><p id=\"deaa\" class=\"pw-post-body-paragraph wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn go bl\" data-selectable-paragraph=\"\">Detecting and understanding environmental changes is essential for informed decision-making, sustainable development, and effective disaster risk reduction. By systematically identifying and monitoring trends such as deforestation, urban expansion, and coastal erosion at an early stage, policymakers, urban planners, environmental agencies, and other relevant stakeholders can implement timely and proactive measures to mitigate adverse impacts on ecosystems, biodiversity, and vulnerable human populations.<\/p><p id=\"bf69\" class=\"pw-post-body-paragraph wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn go bl\" data-selectable-paragraph=\"\">Change detection provides a critical evidence base for assessing the effectiveness of existing environmental policies and conservation strategies. It also plays a key role in informing the planning and development of resilient infrastructure capable of withstanding future environmental stresses. Furthermore, by offering accurate and up-to-date information, it supports more efficient resource allocation and helps prioritize areas facing the greatest risks.<\/p><p id=\"d1ab\" class=\"pw-post-body-paragraph wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn go bl\" data-selectable-paragraph=\"\">Above all, the ability to detect and interpret environmental changes enhances society\u2019s capacity to respond to climate-related challenges such as sea-level rise, extreme weather events, and habitat degradation. In this context, change detection serves as a vital tool for promoting more responsible and adaptive management of the planet in an era marked by rapid and often unpredictable transformation. While this \u201ctime machine\u201d can\u2019t rewrite history, it empowers us to learn from the past and chart a course toward a more sustainable future.<\/p><p id=\"1aac\" class=\"pw-post-body-paragraph wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn go bl\" data-selectable-paragraph=\"\">For today\u2019s adventure, I\u2019m using Databricks and Apache Sedona , they\u2019re basically the power tools for working with geospatial data without your computer having a meltdown. And where are we headed? <strong class=\"wv mb\"><em class=\"xt\">San Francisco,<\/em><\/strong>specifically the <strong class=\"wv mb\"><em class=\"xt\">SoMa (South of Market)<\/em><\/strong> area! We\u2019re gonna see how it looked in August 2022 versus February 2025. Trust me, even in just a couple years, you\u2019d be surprised how much a neighborhood can transform. It\u2019s like watching your city grow up in fast-forward.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5bf0ca0 elementor-widget elementor-widget-heading\" data-id=\"5bf0ca0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Implementation<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e66f2cc elementor-widget elementor-widget-text-editor\" data-id=\"e66f2cc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"ef5f\" class=\"pw-post-body-paragraph xz ya td yb b yc yd ye yf yg yh yi yj rs yk yl ym rv yn yo yp ry yq yr ys yt go bl\" data-selectable-paragraph=\"\">The following implementation is part of the training we offer at RevoData focused specifically on leveraging the geospatial capabilities of Databricks.<\/p><p id=\"3f08\" class=\"pw-post-body-paragraph xz ya td yb b yc yu ye yf yg yv yi yj rs yw yl ym rv yx yo yp ry yy yr ys yt go bl\" data-selectable-paragraph=\"\">Remote sensing and photogrammetry cover a lot of ground, you\u2019ve got active and passive sensors, different types of resolution (spatial, spectral, temporal, radiometric), geo-referencing, orthophoto generation, and electromagnetic spectrum analysis. Instead of getting bogged down in all the technical details, I\u2019m going to focus on why I chose certain methods and what other options could potentially be considered. Let\u2019s get started.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5eb89c2 elementor-widget elementor-widget-heading\" data-id=\"5eb89c2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Datasets<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-587e946 elementor-widget elementor-widget-text-editor\" data-id=\"587e946\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"49c3\" class=\"pw-post-body-paragraph wt wu rx wv b ww wx wy wz xa xb xc xd qm xe xf xg qp xh xi xj qs xk xl xm xn go bl\" data-selectable-paragraph=\"\">First things first, we need data, but what kind? For change detection in an urban environment, we typically rely on satellite or aerial images captured in at least four spectral bands: <strong class=\"wv mb\">Red<\/strong>, <strong class=\"wv mb\">Green<\/strong>, <strong class=\"wv mb\">Blue<\/strong>, and <strong class=\"wv mb\">Near Infrared (NIR)<\/strong>. Why NIR? Well, it all comes down to physics. Different sensors detect different \u2018flavors\u2019 of energy, from visible light our eyes see to invisible infrared or microwave radiation. Each sensor type reveals unique information about Earth\u2019s surface based on the specific energy waves it can measure. What the sensor \u2018sees\u2019 depends on how objects interact with these waves:<\/p><ul class=\"\"><li id=\"6b18\" class=\"wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn anc and ane bl\" data-selectable-paragraph=\"\">Absorption: The surface soaks up the energy (like dark pavement heating in sunlight)<\/li><li id=\"e162\" class=\"wt wu rx wv b ww anf wy wz xa ang xc xd qm anh xf xg qp ani xi xj qs anj xl xm xn anc and ane bl\" data-selectable-paragraph=\"\">Reflection: The energy bounces back (like light mirroring off a lake)<\/li><li id=\"c91b\" class=\"wt wu rx wv b ww anf wy wz xa ang xc xd qm anh xf xg qp ani xi xj qs anj xl xm xn anc and ane bl\" data-selectable-paragraph=\"\">Transmission: The energy passes through (like sunlight through clear water)<\/li><\/ul><p id=\"bd17\" class=\"pw-post-body-paragraph wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn go bl\" data-selectable-paragraph=\"\">Different materials, such as water, soil, concrete, vegetation, each have unique \u2018fingerprints\u2019 in how they handle these waves. That\u2019s how we can identify and monitor features from satellites or aircraft!<\/p><p id=\"de99\" class=\"pw-post-body-paragraph wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn go bl\" data-selectable-paragraph=\"\">These interactions allow us to calculate indices such as the <strong class=\"wv mb\">Normalized Difference Vegetation Index (NDVI)<\/strong> and the <strong class=\"wv mb\">Normalized Difference Water Index (NDWI)<\/strong>. These are simple and useful for classifying each image pixel as vegetation, water, or bare ground. You can also go a step further and apply machine learning or pattern recognition algorithms, like the maximum likelihood classifier, to identify different phenomena across the landscape.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e7a1b98 elementor-widget elementor-widget-text-editor\" data-id=\"e7a1b98\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The good news? This kind of imagery is freely available. You can easily access the data in GeoTiff format through the <a class=\"ah yg\" href=\"https:\/\/coast.noaa.gov\/dataviewer\/#\/\" target=\"_blank\" rel=\"noopener ugc nofollow\"><strong class=\"wv mb\">NOAA Data Access Viewer<\/strong><\/a> and begin your own journey through space and time.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cf0abe0 elementor-widget elementor-widget-image\" data-id=\"cf0abe0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"698\" height=\"318\" src=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-14.52.01.png\" class=\"attachment-large size-large wp-image-6552\" alt=\"\" srcset=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-14.52.01.png 698w, https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-14.52.01-300x137.png 300w, https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-14.52.01-18x8.png 18w\" sizes=\"(max-width: 698px) 100vw, 698px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6a06afb elementor-widget elementor-widget-heading\" data-id=\"6a06afb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Data ingestion<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8b0cc0d elementor-widget elementor-widget-text-editor\" data-id=\"8b0cc0d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Once again, Apache Sedona makes geospatial data ingestion remarkably easy.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ba65271 elementor-widget elementor-widget-code-highlight\" data-id=\"ba65271\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>from pyspark.sql.functions import expr, explode, col\nfrom sedona.spark import *\nfrom pyspark.sql.window import Window\nfrom pyspark.sql import functions as F\nfrom pyspark.sql import SparkSession\n\nconfig = SedonaContext.builder() .\\\n    config('spark.jars.packages',\n           'org.apache.sedona:sedona-spark-shaded-3.3_2.12:1.7.1,'\n           'org.datasyslab:geotools-wrapper:1.7.1-28.5'). \\\n    getOrCreate()\n\nsedona = SedonaContext.create(config)\n\n\nfile_urls = {\"2022\": f\"s3:\/\/{dataset_bucket_name}\/geospatial-dataset\/raster\/orthophoto\/soma\/2022\/2022_4BandImagery_SanFranciscoCA_J1191044.tif\", \n              \"2025\": f\"s3:\/\/{dataset_bucket_name}\/geospatial-dataset\/raster\/orthophoto\/soma\/2025\/2025_4BandImagery_SanFranciscoCA_J1191043.tif\"}\n\ndf_image_2025 = sedona.read.format(\"binaryFile\").load(file_urls[\"2025\"])\ndf_image_2025 = df_image_2025.withColumn(\"raster\", expr(\"RS_FromGeoTiff(content)\"))\n\ndf_image_2022 = sedona.read.format(\"binaryFile\").load(file_urls[\"2022\"])\ndf_image_2022 = df_image_2022.withColumn(\"raster\", expr(\"RS_FromGeoTiff(content)\"))<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9b0ab8c elementor-widget elementor-widget-heading\" data-id=\"9b0ab8c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Exploring the data<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4a5c1b9 elementor-widget elementor-widget-text-editor\" data-id=\"4a5c1b9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>We can retrieve metadata from the 2025 image by executing the following query:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-35335b5 elementor-widget elementor-widget-code-highlight\" data-id=\"35335b5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>\ndf_image_2025.createOrReplaceTempView(\"image_new_vw\")\ndisplay(spark.sql(\"\"\"SELECT RS_MetaData(raster) AS metadata, \n                  RS_NumBands(raster) AS num_bands,\n                  RS_SummaryStatsAll(raster) AS summary_stat,\n                  RS_BandPixelType(raster) AS band_pixel_type,\n                  RS_Count(raster) AS count \n                  FROM image_new_vw\"\"\"))\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-15b136b elementor-widget elementor-widget-spacer\" data-id=\"15b136b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7996431 elementor-widget elementor-widget-heading\" data-id=\"7996431\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Tiling for scalable image analysis<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5feaf67 elementor-widget elementor-widget-text-editor\" data-id=\"5feaf67\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>To improve scalability and enhance performance in the upcoming analysis, we first tile the image into smaller segments:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cf6a429 elementor-widget elementor-widget-code-highlight\" data-id=\"cf6a429\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>\ntile_w = 195\ntile_h = 191\n\ntiled_df_2025 = df_image_2025.selectExpr(\n  f\"RS_TileExplode(raster, {tile_w}, {tile_h})\"\n).withColumnRenamed(\"x\", \"tile_x\").withColumnRenamed(\"y\", \"tile_y\").withColumn(\"width\", expr(\"RS_Width(tile)\")).withColumn(\"height\", expr(\"RS_height(tile)\"))\nwindow_spec = Window.orderBy(\"tile_x\", \"tile_y\")\ntiled_df_2025 = tiled_df_2025.withColumn(\"rn\", F.row_number().over(window_spec)).withColumn(\"year\", lit(2025))\n\ntiled_df_2022 = df_image_2022.selectExpr(\n  f\"RS_TileExplode(raster, {tile_w}, {tile_h})\"\n).withColumnRenamed(\"x\", \"tile_x\").withColumnRenamed(\"y\", \"tile_y\").withColumn(\"width\", expr(\"RS_Width(tile)\")).withColumn(\"height\", expr(\"RS_height(tile)\"))\nwindow_spec = Window.orderBy(\"tile_x\", \"tile_y\")\ntiled_df_2022 = tiled_df_2022.withColumn(\"rn\", F.row_number().over(window_spec)).withColumn(\"year\", lit(2022))\n\nunion_raster = tiled_df_2022.unionByName(tiled_df_2025, allowMissingColumns=False)\nwindow_spec = Window.partitionBy(\"rn\").orderBy(F.desc(\"year\"))\nunion_raster = union_raster.withColumn(\"index\", F.row_number().over(window_spec))<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4d956cd elementor-widget elementor-widget-heading\" data-id=\"4d956cd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Image classification<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d192c1c elementor-widget elementor-widget-text-editor\" data-id=\"d192c1c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"1c3f\" class=\"pw-post-body-paragraph wt wu rx wv b ww wx wy wz xa xb xc xd qm xe xf xg qp xh xi xj qs xk xl xm xn go bl\" data-selectable-paragraph=\"\">We perform pixel-wise classification by calculating the NDVI and NDWI indices and applying a simple decision tree. The classification criteria are informed not only by the definitions of NDVI and NDWI, but also by temporal differences between the two images, which were captured at different times of the year and day. These differences are observable, for instance, in the varying shadows cast by buildings. As with any classification approach, some degree of misclassification is expected. Then the results are written to a Delta table.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8ede838 elementor-widget elementor-widget-code-highlight\" data-id=\"8ede838\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp># Calculating NDVI using Red and NIR bands as NDVI = (NIR - Red) \/ (NIR + Red)\nunion_raster = union_raster.withColumn(\n    \"ndvi\",\n    expr(\n        \"RS_Divide(\"\n        \"  RS_Subtract(RS_BandAsArray(tile, 1), RS_BandAsArray(tile, 4)), \"\n        \"  RS_Add(RS_BandAsArray(tile, 1), RS_BandAsArray(tile, 4))\"\n        \")\"\n    )\n)\n\n\n# Calculating NDWI using Green and NIR bands as NDWI = (Green - NIR) \/ (Green + NIR)\nunion_raster = union_raster.withColumn(\n    \"ndwi\",\n    expr(\n        \"RS_Divide(\"\n        \"  RS_Subtract(RS_BandAsArray(tile, 4), RS_BandAsArray(tile, 2)), \"\n        \"  RS_Add(RS_BandAsArray(tile, 4), RS_BandAsArray(tile, 2))\"\n        \")\"\n    )\n)\n\n# Red and Green bands as arrays in new columns\nunion_raster = union_raster.withColumn(\n    \"red\",\n    expr(\n        \"RS_BandAsArray(tile, 1)\"\n    )\n).withColumn(\n    \"green\",\n    expr(\n        \"RS_BandAsArray(tile, 2)\"\n    )\n)\n\n\n# Classification tree based on Red and Green bands and NDVI, NDWI\nunion_raster = union_raster.withColumn(\n    \"classification\",\n    F.expr(\"\"\"\n        transform(\n            arrays_zip(ndvi, ndwi, red, green),\n            x -> \n                CASE \n                    WHEN year = 2022 THEN\n                        CASE \n                            WHEN x.red < 15 AND x.green < 15 THEN 4\n                            WHEN x.ndvi > 0.35 AND x.ndwi < -0.35 THEN 2\n                            WHEN (x.ndvi < -0.2 AND x.ndwi > 0.35) OR (x.red < 15 AND x.ndwi > 0.35) OR (x.ndwi > 0.45) THEN 3\n                            WHEN x.ndvi >= -0.3 AND x.ndvi <= 0.3 AND x.ndwi >= -0.3 AND x.ndwi <= 0.3 THEN 1\n                            ELSE 999\n                        END\n                    WHEN year = 2025 THEN\n                        CASE \n                            WHEN x.red < 15 AND x.green < 15 THEN 4\n                            WHEN x.ndvi > 0.3 AND x.ndwi < -0.15 THEN 2\n                            WHEN x.ndvi < -0.35 AND x.ndwi > 0.55 THEN 3\n                            WHEN (x.ndvi >= -0.5 AND x.ndvi <= 0.5 AND x.ndwi >= -0.5 AND x.ndwi <= 0.5) OR (x.ndvi > 0.8 AND x.ndwi > 0.3) THEN 1                           \n                            ELSE 999\n                        END\n                    ELSE 999\n                END\n        )\n    \"\"\")\n)\n\n# Classification array as a new band in the raster and defining no data value as 999 \nclassification_df = (\n    union_raster\n    .select(\"tile_x\", \"tile_y\", \"rn\", \"year\", \"index\", expr(\"RS_MakeRaster(tile, 'I', classification) AS tile\").alias(\"tile\"))\n    .select(\"tile_x\", \"tile_y\", \"rn\", \"year\", \"index\", expr(\"RS_SetBandNoDataValue(tile,1, 999, false)\").alias(\"tile\"))\n    .select(\"tile_x\", \"tile_y\", \"rn\", \"year\", \"index\", expr(\"RS_SetBandNoDataValue(tile,1, 999, true)\").alias(\"tile\"))\n)\n\nclassification_df = classification_df.withColumn(\"maxValue\", expr(\"\"\"RS_SummaryStats(tile, \"max\", 1, false)\"\"\"))\n\nclassification_df.withColumn(\"raster_binary\", expr(\"RS_AsGeoTiff(tile)\")).select(\"tile_x\", \"tile_y\",\"rn\", \"year\", \"index\", \"raster_binary\").write.mode(\"overwrite\").saveAsTable(\"geospatial.soma.classification\")<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ba7bb91 elementor-widget elementor-widget-image\" data-id=\"ba7bb91\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"712\" height=\"382\" src=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.08.17.png\" class=\"attachment-large size-large wp-image-6556\" alt=\"\" srcset=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.08.17.png 712w, https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.08.17-300x161.png 300w, https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.08.17-18x10.png 18w\" sizes=\"(max-width: 712px) 100vw, 712px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-602d0b4 elementor-widget elementor-widget-heading\" data-id=\"602d0b4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Filling missing data via interpolation<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-42fdee6 elementor-widget elementor-widget-text-editor\" data-id=\"42fdee6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>In the images above, we can observe white areas, i.e. pixels that couldn\u2019t be classified and were left as no-data values. To address this, we can apply interpolation using the Inverse Distance Weighting (IDW) method. Apache Sedona simplifies this process: we filter out the tiles with no-data values and perform the interpolation. After that, we store the interpolated results in a Delta table.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b420ae7 elementor-widget elementor-widget-code-highlight\" data-id=\"b420ae7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>\n\n# Separating the dataframe into two dataframes based on the \nno_interpolation_df = classification_df.filter(classification_df[\"maxValue\"] != 999).select(\"tile_x\", \"tile_y\",\"rn\", \"year\", \"index\", \"raster_binary\")\ninterpolated_df = classification_df.filter(classification_df[\"maxValue\"] == 999).select(\"tile_x\", \"tile_y\",\"rn\", \"year\", \"index\", expr(\"RS_Interpolate(tile, 2.0, 'variable', 48.0, 6.0)\").alias(\"tile\")).withColumn(\"raster_binary\", expr(\"RS_AsGeoTiff(tile)\")).select(\"tile_x\", \"tile_y\",\"rn\", \"year\", \"index\", \"raster_binary\")\nunion_df = interpolated_df.unionByName(no_interpolation_df, allowMissingColumns=False)\nunion_df.write.mode(\"overwrite\").saveAsTable(\"geospatial.soma.interpolation\")\nunion_df = spark.table(\"geospatial.soma.interpolation\").withColumn(\"tile\", expr(\"RS_FromGeoTiff(raster_binary)\"))\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8f55a68 elementor-widget elementor-widget-image\" data-id=\"8f55a68\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"711\" height=\"367\" src=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.09.31.png\" class=\"attachment-large size-large wp-image-6557\" alt=\"\" srcset=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.09.31.png 711w, https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.09.31-300x155.png 300w, https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.09.31-18x9.png 18w\" sizes=\"(max-width: 711px) 100vw, 711px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6f6d5f7 elementor-widget elementor-widget-heading\" data-id=\"6f6d5f7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Evaluating classification changes between the two images\n<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1d2428d elementor-widget elementor-widget-text-editor\" data-id=\"1d2428d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"678a\" class=\"pw-post-body-paragraph wt wu rx wv b ww wx wy wz xa xb xc xd qm xe xf xg qp xh xi xj qs xk xl xm xn go bl\" data-selectable-paragraph=\"\">It would be useful to create a band that highlights the differences between the classifications from 2022 and 2025, and add it as the third band in the image.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c2c62a0 elementor-widget elementor-widget-code-highlight\" data-id=\"c2c62a0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>\nunion_df.createOrReplaceTempView(\"union_df_vw\")\n\nmerged_raster = sedona.sql(\"\"\"\n    SELECT rn, RS_Union_Aggr(tile, index) AS raster\n    FROM union_df_vw\n    GROUP BY rn\n\"\"\")\n\nmerged_raster.createOrReplaceTempView(\"merged_raster_vw\")\ndiff_raster = merged_raster.withColumn(\"diff_band\", expr( \n        \"RS_LogicalDifference(\"\n        \"RS_BandAsArray(raster, 1), RS_BandAsArray(raster, 2)\"\n        \")\"))\n\nresult_df = diff_raster.select(\"rn\", expr(\"RS_AddBandFromArray(raster, diff_band) AS raster\").alias(\"raster\")).withColumn(\"raster_binary\", expr(\"RS_AsGeoTiff(raster)\"))\nresult_df.select(\"rn\", \"raster_binary\").write.mode(\"overwrite\").saveAsTable(\"geospatial.soma.change_detection\")<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-42c5ac0 elementor-widget elementor-widget-text-editor\" data-id=\"42c5ac0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Finally, we can detect and visualize changes, such as those in vegetation, using the image below as an example:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6cc3da0 elementor-widget elementor-widget-image\" data-id=\"6cc3da0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"708\" height=\"614\" src=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.11.25.png\" class=\"attachment-large size-large wp-image-6558\" alt=\"\" srcset=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.11.25.png 708w, https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.11.25-300x260.png 300w, https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2026-01-23-at-15.11.25-14x12.png 14w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4da69e7 elementor-widget elementor-widget-heading\" data-id=\"4da69e7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">What is next? <\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-16b095a elementor-widget elementor-widget-text-editor\" data-id=\"16b095a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"a57f\" class=\"pw-post-body-paragraph wt wu rx wv b ww wx wy wz xa xb xc xd qm xe xf xg qp xh xi xj qs xk xl xm xn go bl\" data-selectable-paragraph=\"\"><strong class=\"wv mb\">In our live training <em class=\"xt\">\u201c<\/em><\/strong><a class=\"ah yg\" href=\"https:\/\/revodata.nl\/databricks-geospatial-in-a-day\/\" target=\"_blank\" rel=\"noopener ugc nofollow\"><strong class=\"wv mb\"><em class=\"xt\">Databricks Geospatial in a Day<\/em><\/strong><\/a><strong class=\"wv mb\"><em class=\"xt\">\u201d<\/em> at RevoData Office<\/strong>, we\u2019ll delve deeper into the logic behind this code and use this example to demonstrate how to:<\/p><ul class=\"\"><li id=\"af8e\" class=\"wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn anc and ane bl\" data-selectable-paragraph=\"\">Visualize GeoTIFF files<\/li><li id=\"5be9\" class=\"wt wu rx wv b ww anf wy wz xa ang xc xd qm anh xf xg qp ani xi xj qs anj xl xm xn anc and ane bl\" data-selectable-paragraph=\"\">Generate optimally sized tiles from large raster datasets<\/li><li id=\"cc58\" class=\"wt wu rx wv b ww anf wy wz xa ang xc xd qm anh xf xg qp ani xi xj qs anj xl xm xn anc and ane bl\" data-selectable-paragraph=\"\">Configure clusters optimized for compute-intensive workloads, such as spatial interpolation<\/li><li id=\"4bf0\" class=\"wt wu rx wv b ww anf wy wz xa ang xc xd qm anh xf xg qp ani xi xj qs anj xl xm xn anc and ane bl\" data-selectable-paragraph=\"\">Partition Spark DataFrames by the raster column to accelerate processing<\/li><li id=\"4667\" class=\"wt wu rx wv b ww anf wy wz xa ang xc xd qm anh xf xg qp ani xi xj qs anj xl xm xn anc and ane bl\" data-selectable-paragraph=\"\">Use complementary tools to seamlessly merge tiles back into a single large GeoTIFF<\/li><\/ul><p id=\"1825\" class=\"pw-post-body-paragraph wt wu rx wv b ww xo wy wz xa xp xc xd qm xq xf xg qp xr xi xj qs xs xl xm xn go bl\" data-selectable-paragraph=\"\"><strong class=\"wv mb\">Go ahead and grab your spot for the training using the link below, can\u2019t wait to see you there!<\/strong><br \/><a class=\"ah yg\" href=\"https:\/\/revodata.nl\/databricks-geospatial-in-a-day\/\" target=\"_blank\" rel=\"noopener ugc nofollow\"><em class=\"xt\">https:\/\/revodata.nl\/databricks-geospatial-in-a-day\/<\/em><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-20b8a1c elementor-widget elementor-widget-spacer\" data-id=\"20b8a1c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-96a198e elementor-author-box--layout-image-left elementor-author-box--align-left elementor-widget elementor-widget-author-box\" data-id=\"96a198e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"author-box.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-author-box\">\n\t\t\t\t\t\t\t<div  class=\"elementor-author-box__avatar\">\n\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/revodata.nl\/wp-content\/uploads\/Screenshot-2025-09-08-at-14.16.05-288x300.png\" alt=\"Foto van Melika Sajadian\" loading=\"lazy\">\n\t\t\t\t<\/div>\n\t\t\t\n\t\t\t<div class=\"elementor-author-box__text\">\n\t\t\t\t\t\t\t\t\t<div >\n\t\t\t\t\t\t<h4 class=\"elementor-author-box__name\">\n\t\t\t\t\t\t\tMelika Sajadian\t\t\t\t\t\t<\/h4>\n\t\t\t\t\t<\/div>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-author-box__bio\">\n\t\t\t\t\t\t<p>Senior Geospatial Consultant at RevoData, sharing with you her knowledge about Databricks Geospatial <\/p>\n\t\t\t\t\t<\/div>\n\t\t\t\t\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-7f92b56 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"7f92b56\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-9518311\" data-id=\"9518311\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Editor&#8217;s note: This post was originally published June 12th, 2025.\u00a0 What is environmental change detection? Think of it as a time machine for planet Earth. No flux capacitor, no DeLorean, and no Marty McFly needed!\ud83d\ude09 Just some cool tech that lets us peek into how our world changes over time. Detecting and understanding environmental changes [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":6550,"comment_status":"open","ping_status":"closed","sticky":false,"template":"elementor_theme","format":"standard","meta":{"content-type":"","footnotes":""},"categories":[14,21,28],"tags":[],"class_list":["post-6551","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-it","category-databricks","category-geospatial"],"_links":{"self":[{"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/posts\/6551","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/comments?post=6551"}],"version-history":[{"count":3,"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/posts\/6551\/revisions"}],"predecessor-version":[{"id":6561,"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/posts\/6551\/revisions\/6561"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/media\/6550"}],"wp:attachment":[{"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/media?parent=6551"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/categories?post=6551"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/revodata.nl\/nl\/wp-json\/wp\/v2\/tags?post=6551"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}