From 0a9d8bd8a16ab3d34fab201d8fdac5d673be261d Mon Sep 17 00:00:00 2001 From: Stuart Lynn <50170698+sllynn@users.noreply.github.com> Date: Tue, 24 Sep 2024 20:58:37 +0100 Subject: [PATCH] added gdal UDF example to docs (#579) --- docs/source/api/api.rst | 2 +- ...sterio-udfs.rst => rasterio-gdal-udfs.rst} | 83 +++++++++++++++++- docs/source/images/rasterio/quadbin.png | Bin 0 -> 34902 bytes 3 files changed, 80 insertions(+), 5 deletions(-) rename docs/source/api/{rasterio-udfs.rst => rasterio-gdal-udfs.rst} (87%) create mode 100644 docs/source/images/rasterio/quadbin.png diff --git a/docs/source/api/api.rst b/docs/source/api/api.rst index 5d4401fac..6503f91db 100644 --- a/docs/source/api/api.rst +++ b/docs/source/api/api.rst @@ -13,4 +13,4 @@ API Documentation spatial-predicates spatial-aggregations raster-functions - rasterio-udfs \ No newline at end of file + rasterio-gdal-udfs \ No newline at end of file diff --git a/docs/source/api/rasterio-udfs.rst b/docs/source/api/rasterio-gdal-udfs.rst similarity index 87% rename from docs/source/api/rasterio-udfs.rst rename to docs/source/api/rasterio-gdal-udfs.rst index 46cf46f77..e82c181da 100644 --- a/docs/source/api/rasterio-udfs.rst +++ b/docs/source/api/rasterio-gdal-udfs.rst @@ -1,5 +1,5 @@ ===================== -Rasterio UDFs +Rasterio + GDAL UDFs ===================== @@ -12,7 +12,8 @@ It is a great library for working with raster data in Python and it is a popular Rasterio UDFs provide a way to use Rasterio Python API in Spark for distributed processing of raster data. The data structures used by Mosaic are compatible with Rasterio and can be used interchangeably. In this section we will show how to use Rasterio UDFs to process raster data in Mosaic + Spark. -We assume that you have a basic understanding of Rasterio and GDAL. +We assume that you have a basic understanding of Rasterio and GDAL. We also provide an example which directly calls GDAL +Translate and Warp. Please note that we advise the users to set these configuration to ensure proper distribution. @@ -22,7 +23,7 @@ Please note that we advise the users to set these configuration to ensure proper spark.conf.set("spark.sql.execution.arrow.maxRecordsPerBatch", "1024") spark.conf.set("spark.sql.execution.arrow.fallback.enabled", "true") spark.conf.set("spark.sql.adaptive.coalescePartitions.enabled", "false") - spark.conf.set("spark.sql.shuffle.partitions", "400") + spark.conf.set("spark.sql.shuffle.partitions", "400") # maybe higher, depending Rasterio raster plotting @@ -238,7 +239,7 @@ Next we will define a function that will write a given raster file to disk. A "g not want to have a file context manager open when you go to write out its context as the context manager will not yet have been flushed. Another "gotcha" might be that the raster dataset does not have CRS included; if this arises, we recommend adjusting the function to specify the CRS and set it on the dst variable, more at -`rasterio.crs `_. We would also point out that notional +`rasterio.crs `__. We would also point out that notional "file_id" param can be constructed as a repeatable name from other field(s) in your dataframe / table or be random, depending on your needs. @@ -355,3 +356,77 @@ Finally we will apply the function to the DataFrame. | /dbfs/path/to/output/dir/3215.tif | | ... | +-------------------------------------------+ + + +UDF example for generating Google Maps compatible tiles +####################################################### + +Delta Tables can be used as the basis for serving pre-generated tiles as an option. Here is an example UDF that applies +a few gdal operations on each band, to write to Google Maps Compatible tiles transformed into 3857 (Web Mercator). Note: +the 'quadbin' column shown in this example was generated separately using CARTO's `quadbin `__ +package. You can replace the calls with whatever you need to do. The output structure looks something like the following: + +.. figure:: ../images/rasterio/quadbin.png + :figclass: doc-figure + +The UDF example sets raster extent, block size, and interpolation. It specifies source SRID as 4326; +additionally, output type and nodata values are specified. COG overviews are not generated +nor is an ALPHA band, but they could be. Again, you would modify this example to suit your needs. + +.. code-block:: python + + @udf("binary") + def transform_raw_raster(raster): + import tempfile + import uuid + from osgeo import gdal + + with tempfile.TemporaryDirectory() as tmp_dir: + fn1 = f"{tmp_dir}/{uuid.uuid4().hex}.tif" + fn2 = f"{tmp_dir}/{uuid.uuid4().hex}.tif" + fn3 = f"{tmp_dir}/{uuid.uuid4().hex}.tif" + fn4 = f"{tmp_dir}/{uuid.uuid4().hex}.tif" + + with open(fn1, "wb") as f: + f.write(raster) + + gdal.Translate(fn2, fn1, options="-of GTiff -a_ullr -180 90 180 -90 -a_nodata -32767 -ot Int16") + gdal.Warp(fn3, fn2, options= "-tr 0.125 -0.125 -r cubicspline") + gdal.Warp(fn4, fn3, options= "-of COG -co BLOCKSIZE=1024 -co TILING_SCHEME=GoogleMapsCompatible -co COMPRESS=DEFLATE -co OVERVIEWS=NONE -co ADD_ALPHA=NO -co RESAMPLING=cubicspline -s_srs EPSG:4326") + + with open(fn4, "rb") as f: + res = f.read() + return res + +Example of calling the UDF (original data was NetCDF). If you have more than 1 band, this assumes :code:`transform_raw_rasters` UDF is called after +:code:`rst_separatebands` function (or you could potentially modify the UDF to operate on multiple bands). + +.. code-block:: python + + base_table = ( + df + .select( + "path", + "metadata", + "tile" + ) + .withColumn("subdatasets", mos.rst_subdatasets("tile")) + .where(F.array_contains(F.map_values("subdatasets"), "sfcWind")) + .withColumn("tile", mos.rst_getsubdataset("tile", F.lit("sfcWind"))) + .withColumn("tile", mos.rst_separatebands("tile")) + .repartition(sc.defaultParallelism) + .withColumn( + "tile", + F.col("tile") + .withField("raster", transform_raw_raster("tile.raster")) + .withField( + "metadata", + F.map_concat("tile.metadata", F.create_map(F.lit("driver"), F.lit("GTiff"))) + ) + ) + .withColumn("srid", mos.rst_srid("tile")) + .withColumn("srid", F.when(F.col("srid") == F.lit(0), F.lit(4326)).otherwise(F.col("srid"))) + .withColumn("timestep", F.element_at(mos.rst_metadata("tile"), "NC_GLOBAL#GDAL_MOSAIC_BAND_INDEX")) + .withColumn("tile", mos.rst_transform("tile", F.lit(3857))) + .repartition(sc.defaultParallelism, "timestep") + ) diff --git a/docs/source/images/rasterio/quadbin.png b/docs/source/images/rasterio/quadbin.png new file mode 100644 index 0000000000000000000000000000000000000000..066136feb31db3dcbb9562637e9e7426e39640db GIT binary patch literal 34902 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