Skip to main content

RasterX Function Reference

RasterX functions run in two execution tiers — lightweight (pure-Python pyrx) and heavyweight (rasterx). As of v0.4.0, every RasterX function is available in both tiers (badged <Tier both/> per function below); per-function notes call out where the lightweight implementation differs. See Choosing an Execution Tier for the comparison and the lightweight install.

Complete reference for all RasterX functions with detailed descriptions, parameters, return values, and examples.

Built on rasterio

RasterX's lightweight tier is, in large part, distributed rasterio + a best-of-breed raster stack. See Rasterio Distributed for the coverage matrix and honest gaps.

Overview

RasterX is GeoBrix's raster data processing package, providing comprehensive tools for working with raster datasets such as satellite imagery, elevation models, and other gridded spatial data. It is a refactor and improvement of Mosaic raster functions, extended through v0.5.0 with terrain analysis, spectral indices, vector-raster bridging, web-mercator tile output, H3/quadbin/BNG grid aggregations, and — in v0.5.0 — virtual tiles, a COG-preparation lane, and VRT mosaics for memory-safe processing of multi-gigabyte rasters. Since the Databricks product does not (yet) support anything built-in specifically for raster processing, RasterX provides a gap-filling capability for raster operations on the Databricks platform.

Key Features

  • GDAL-Powered: Leverages GDAL for robust raster format support
  • Distributed Processing: Built on Spark for scalable raster operations
  • Multiple Format Support: GeoTIFF, COG, NetCDF, and other GDAL-supported formats
  • Metadata Extraction: Comprehensive raster metadata access
  • Raster Operations: Clipping, resampling, transformations, map algebra
  • Band Operations: Multi-band raster support, single-band extraction
  • Terrain Analysis: Slope, aspect, hillshade, TRI, TPI, roughness, color-relief
  • Spectral Indices: EVI, SAVI, NDWI, NBR, NDVI, plus a generic dispatcher
  • Vector-Raster Bridge: Rasterize geometries, polygonize value regions
  • Tile Publishing: Web-mercator XYZ tile generation (PNG / JPEG / WebP)
  • Grid Aggregations: H3, CARTO quadbin v0, and BNG cell aggregations
  • Virtual Tiles: Bytes-free windowed reads — process multi-gigabyte rasters without materializing them into executor memory
  • COG Preparation & VRT Mosaics: file_gbx + cog_gbx prepare spec-valid Cloud-Optimized GeoTIFFs and portable VRT mosaics for cheap windowed reads

Function Categories

RasterX exposes 129 SQL functions (registered as gbx_rst_*; available in Python and Scala as rst_*), organized into the following categories (see rasterx/functions.scala):

RasterX function categories — Constructors, Accessors, Aggregators, Generators, Operations, H3 Grid

  • Accessor Functions: Read raster properties and metadata (bounds, dimensions, CRS, bands, pixel size, georeference, format, type, NoData, subdatasets, summary, etc.)
  • Aggregator Functions: Combine or merge rasters in group-by (combineavg_agg, derivedband_agg, merge_agg, h3_rasterize_agg)
  • Constructor Functions: Create or load rasters from paths, binary content, or bands
  • Generator Functions: Produce multiple tiles or bands (h3_tessellate, maketiles, retile, separatebands, tooverlappingtiles)
  • Grid Functions (H3): Aggregate raster values to H3 cells (rastertogrid avg/count/max/min/median/sum/variance/stddev)
  • Grid Functions (quadbin): Aggregate raster values to CARTO quadbin v0 cells (rastertogrid avg/count/max/min/median/sum/variance/stddev; tessellate; rasterize_agg)
  • Grid Functions (BNG): Aggregate raster values to British National Grid cells (rastertogrid avg/count/max/min/median/sum/variance/stddev; tessellate; rasterize_agg)
  • Operations: Transform and analyze rasters (clip, transform, merge, asformat, ndvi, filter, convolve, map algebra, coordinate conversion, isEmpty, tryOpen, initNoData, updateType, combineavg, derivedband)
  • Web-Mercator Tile Output: Reproject to EPSG:3857 and emit slippy-map XYZ tiles (to_webmercator, tilexyz, xyzpyramid)
  • Vector-raster bridge: Burn polygons into rasters and trace contiguous regions back to polygons (rasterize, polygonize)
  • Terrain Analysis: DEM-derived surfaces from gdal.DEMProcessing (slope, aspect, hillshade, TRI, TPI, roughness, color relief)
  • Spectral Indices: Multi-band satellite math (EVI, SAVI, NDWI, NBR, plus the generic rst_index dispatcher)

Tile payload

Every RasterX (heavyweight) function returns a materialized tile whose raster field is a self-contained, in-memory raster (GTiff by default) — safe to serialize between Spark stages and executors, persist to Delta, hand off to rasterio / gdal, or write back out via the gdal writer. The bytes are never an XML reference to a per-executor /vsimem/ tempfile or to a path that only exists on the producing node.

See Tile structure for the full tile-struct schema (the shared cellid / raster / path / window / … struct), and Virtual Tiles for the bytes-free lightweight-tier variant and how tiles move between materialized and virtual.

Functions that internally build via an intermediate VRT — gbx_rst_merge, gbx_rst_merge_agg, gbx_rst_frombands, gbx_rst_combineavg, gbx_rst_combineavg_agg, gbx_rst_derivedband, gbx_rst_derivedband_agg — materialize the result to GTiff before returning, so downstream stages on different executors see real raster bytes. Inspect a tile's payload format from tile.metadata.driver; for any of the functions above, it will read GTiff (not VRT). See Release Notes for the v0.3.0 correctness fix that introduced this invariant. See Tile structure for the full tile-struct schema.

Virtual-tile force-output params

Virtual-tile force-output params — lightweight tier only

Tile-returning rst_* functions in the lightweight tier accept three optional keyword arguments that control whether the produced tile carries raster bytes or a bytes-free virtual reference (a path + window instead of in-memory pixels):

ArgumentTypeMeaning
virtualize_dirstr (durable path)Write the produced tile to <dir>/[<prefix>_]<name>.tif and return a virtual tile (path + window, no bytes). The directory must be a durable, executor-readable location such as a Unity Catalog Volume path. Cannot be set together with materialize=True.
virtualize_prefixstrOptional filename prefix added before the provenance-based filename — use this to deconflict when two different function outputs share the same virtualize_dir.
materializeboolTrue — ensure the produced tile carries bytes. False — no-op. Default (unset) — auto: reference/passthrough ops (header reads, rst_clip, rst_setsrid, identity rst_transform) belong to the no-new-pixels class and incur no pixel computation; pixel-producing ops (slope, focal, mapalgebra, reproject, merge, combineavg, frombands, …) materialize.

Default (auto) behavior: reference/passthrough operations (rst_clip, rst_setsrid, identity rst_transform) produce no new pixels — they describe a region of or annotation on existing backing data rather than computing fresh values, so they are the low-cost class. Pixel-producing operations (slope, focal, mapalgebra, reproject, merge, combineavg, frombands, …) materialize and return bytes; for these, virtualize_dir is the only way to get a virtual tile back — it writes the computed result to a durable path and returns a light virtual row.

The lightweight tier is for light (virtual) raster tiles; the heavyweight tier is for heavy (binary) raster tiles. The heavyweight (rasterx) tier does not accept virtualize_dir, virtualize_prefix, or materialize, and accepts only materialized tiles (raster bytes present) as input — both v1 and v2 materialized tiles are accepted; the result is always the v2 tile struct. Passing a virtual tile to a heavyweight function raises a clear error directing you to materialize it first. For most raster work the lightweight tier covers the full function set and is the recommended default. If you specifically need a heavyweight function, materialize the tile first (materialize=True, or write via a writer, which always materializes) before passing it. See Virtual tiles and the light→heavy bridge for details.

Setup

With the geobrix library already installed (Installation), pick your execution tier and run this once. Both tiers alias the module as rx, so every example below is identical regardless of tier — only this setup differs. (See Choosing an Execution Tier for the comparison.)

The examples on this page read from four temp views, each a raster loaded as a tile column. Point the four path placeholders at your own rasters:

PlaceholderSample fileReader (light / heavy) — Temp viewBacks
GTIFF_SAMPLE_DIRsingle-band GeoTIFFgtiff_gbx / gtiff_gdalrastersDefault — most accessor, tile-ops, transform, and generator examples
GTIFF_MULTI_DIRmulti-band GeoTIFF (red/NIR/green)gtiff_gbx / gtiff_gdalmultiband_rastersband-math and spectral-index examples, rst_numbands, rst_bandmetadata
DTM_DIRdigital elevation modelgtiff_gbx / gtiff_gdaldem_rastersterrain examples (rst_slope, rst_aspect, …)
NETCDF_DIRNetCDF with subdatasetsnetcdf_gbx / netcdf_gdalnetcdf_rastersrst_subdatasets, rst_getsubdataset

Each format has a named reader in both tiers (light *_gbx / heavy *_gdal); the setup for each tier below uses its own. The generic readers (raster_gbx light, gdal heavy) also read any raster their tier's engine supports.

The four *_DIR placeholders in the code below are wired to small sample rasters committed in the GeoBrix repo under src/test/resources/binary/ (resolved by the _SAMPLE_PATHS[...] / *_path() helpers you'll see in the snippet). To run the examples yourself, stage those sample files — or your own rasters — in a Unity Catalog Volume directory and set each placeholder to its Volume path.

The setup below loads GTIFF_SAMPLE_DIR into rasters and then loads the other three the same way — swap the path and view name (and, for NetCDF, the reader). Every example on the page assumes these four views exist.

Lightweight setup (pyrx)
from databricks.labs.gbx.pyrx import functions as rx
from databricks.labs.gbx.ds.register import register as register_readers

rx.register(spark)
# Register the lightweight Python DataSource readers (raster_gbx / gtiff_gbx /
# netcdf_gbx / cog_gbx). Pure-Python, no JAR — the light-tier counterpart of the
# heavy gdal / gtiff_gdal / netcdf_gdal readers.
register_readers(spark)

GTIFF_SAMPLE_DIR = _SAMPLE_PATHS["gtiff"]
GTIFF_MULTI_DIR = _SAMPLE_PATHS["gtiff_multi"]
DTM_DIR = _SAMPLE_PATHS["dtm"]
NETCDF_DIR = _SAMPLE_PATHS["netcdf"]

def load_tiles(path, reader, view):
df = spark.read.format(reader).load(path)
df.createOrReplaceTempView(view)
return df

# Load the default single-band raster into the `rasters` view:
rasters = load_tiles(GTIFF_SAMPLE_DIR, "gtiff_gbx", "rasters")

# The other three load the same way — GeoTIFFs use "gtiff_gbx", NetCDF uses "netcdf_gbx":
load_tiles(GTIFF_MULTI_DIR, "gtiff_gbx", "multiband_rasters")
load_tiles(DTM_DIR, "gtiff_gbx", "dem_rasters")
load_tiles(NETCDF_DIR, "netcdf_gbx", "netcdf_rasters")
Example output
Four temp views created — `rasters` (single-band), `multiband_rasters`,
`dem_rasters`, and `netcdf_rasters` — each a DataFrame with a `tile` column.
Every example on this page reads from one of these views.

Tier availability

As of v0.4.0, all RasterX functions run in both execution tiers — the lightweight pyrx (pure-Python) and heavyweight rasterx tiers share the same rst_* / gbx_rst_* names, and each function below carries a :::note Lightweight tier (pyrx) admonition with its backing library and any behavioral differences. For the heavyweight VRT Python pixel-function configuration (used by gbx_rst_combineavg / gbx_rst_derivedband), see VRT Python pixel functions at the end of this page.

Examples — Conventions

Every function on this page shows one example, expressed identically across four tabs. This section defines the shared setup so each function tab contains only its invocation — nothing more.

Canonical sample files

Each function uses one of four canonical files, chosen by what the function demonstrates:

FileWhat it demonstratesUsed by
nyc_sentinel2_red.tifSingle-band GeoTIFF (Sentinel-2 red band, NYC area)Default — most accessor, tile-ops, transform, and generator functions
rgb_nir_small.tif3-band GeoTIFF with per-band metadata (red, NIR, green — 8×8 px)Band-math and spectral-index functions (rst_ndvi, rst_evi, …), rst_numbands, rst_bandmetadata
srtm_n40w073.tifDigital Elevation Model (SRTM, NYC area)Terrain functions (rst_slope, rst_aspect, rst_hillshade, …)
CMIP5 NetCDF (prAdjust_day_…nc)Multi-variable NetCDF with two subdatasetsrst_subdatasets, rst_getsubdataset only

The tile-column convention

In every example on this page:

  • SQL: rasters is a temporary view whose tile column holds the canonical sample loaded via the reader. FROM rasters means "the sample as tiles."
  • Python (light and heavy): df is a DataFrame with a tile column loaded from the canonical file. df.select(...) means "apply this function to the sample tiles."
  • Scala: rasters is a DataFrame with the same tile column. rasters.select(...) is identical in intent to the Python form.

Each function's example therefore shows only the invocation — the load is the convention, not the code.

How to read the four tabs

TabTierColor
SQLBoth (default)
Python (light)pyrx lightweight tier
Python (heavy)rasterx heavyweight tierBlue badge
Scalarasterx heavyweight tierBlue badge

All four tabs show the same operation on the same file. Where a tier's output genuinely differs in form, a short note explains why — for example:

  • Geometry-returning functions (rst_boundingbox, rst_georeference): SQL returns WKT; Python and Scala return a binary column. The note reads ... (WKB binary).
  • Subdataset maps (rst_subdatasets): SQL returns map<string,string>; rendered as {SUBDATASET_1_NAME -> ..., SUBDATASET_1_DESC -> ...}. A note clarifies the key pattern.
  • Band-metadata maps (rst_bandmetadata): similarly noted where the rendering differs between tiers.

Scalar values are identical across all tabs — same fixture, same function, same result.

Tile-returning functions (rst_clip, rst_resample, rst_transform, the aggregators, the constructors, …) return a v2 Tile. Their output is shown as a representative struct — {0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}} — rather than a literal byte dump. Tiles loaded via rst_fromcontent / rst_fromfile (as in Setup) are materialized: the raster field holds the encoded bytes and path is null. Virtual tiles — a populated path with lazily-read bytes — arise from the force-output parameters, not from the default load.

SQL naming and arguments: in the SQL tab, RasterX functions carry the gbx_ prefix (e.g. gbx_rst_boundingbox, gbx_rst_width); Python and Scala use the bare rst_* name via rx. In the lightweight tier the registered gbx_rst_* SQL functions require every argument to be passed explicitly — optional defaults are honored only through the Python rx.* API. See Language Bindings for more.

Per-function notes

Functions that use a non-default fixture (multiband GeoTIFF, DEM, or NetCDF) carry a one-line note immediately before their code example flagging the file. Functions that produce a tile rather than consuming one (constructors: rst_fromfile, rst_fromcontent, rst_frombands, …) show a fuller load/build example with a note — the bare-invocation model does not apply when there is no input tile yet.

Accessor Functions

Functions to read raster properties and metadata (29 total).

rst_avg

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Per-band mean over valid (non-NoData) pixels.

Signature: rst_avg(tile: Column): Column — Per-band average pixel values.

Returns NULL for a band with zero valid pixels (all NoData) on both tiers.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands: red, NIR, green); the canonical single-band sentinel2 tile is all-NoData for this function.

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_avg(tile) AS band_averages FROM multiband_rasters;
Example output
+-----------------------------+
|band_averages |
+-----------------------------+
|[83.59375, 153.125, 114.3125]|
+-----------------------------+

rst_bandmetadata

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_bandmetadata(tile: Column, band: Column): Column — Band metadata map.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands with per-band GDAL metadata tags); plain single-band GeoTIFFs without tags return an empty map {}.

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_bandmetadata(tile, 1) AS band_meta FROM multiband_rasters;
Example output
+----------------------------------------------+
|band_meta |
+----------------------------------------------+
|{name -> red, wavelength_nm -> 665, band_in...|
+----------------------------------------------+

rst_boundingbox

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_boundingbox(tile: Column): Column — Bounding box geometry.

SELECT path, gbx_rst_boundingbox(tile) as bbox FROM rasters;
Example output
+--------------------+-----------------+
|path |bbox |
+--------------------+-----------------+
|.../nyc_sentinel2...|POLYGON ((-74....|
+--------------------+-----------------+

rst_crs

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + pyproj.

Signature: rst_crs(tile: Column): Column — the tile's CRS as a string (authority string like EPSG:4326 / ESRI:54008, else WKT); always returns a value, including for non-EPSG rasters where rst_srid is NULL. See Coordinate Reference Systems.

Returns the authority string (AUTHORITY:CODE, e.g. EPSG:4326 or ESRI:54008) when the CRS has one, otherwise its WKT. Unlike rst_srid (which returns the integer EPSG code, or NULL/0 for a CRS with no EPSG code), rst_crs always returns a value — including for non-EPSG rasters defined by an ESRI code, WKT, or PROJ4 string.

CRS: SRID int vs CRS string
  • rst_srid returns the integer EPSG code (e.g. 4326); NULL (lightweight) or 0 (heavyweight) when the CRS has no EPSG code. Use it when you need the numeric SRID for the native ST bridge or an EPSG-only workflow.
  • rst_crs returns the CRS string and never loses a non-EPSG CRS.
  • rst_setcrs / rst_transformcrs take a CRS string. An int-castable string is treated as an EPSG SRID ('4326' behaves like SRID 4326); otherwise the string is parsed as an authority code (EPSG:/ESRI:), WKT, or PROJ4. This is how ESRI codes, WKT, and PROJ4 definitions survive a round trip.
SELECT gbx_rst_crs(tile) AS crs FROM rasters;
Example output
+----------+
|crs |
+----------+
|EPSG:32618|
+----------+

rst_format

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_format(tile: Column): Column — GDAL format name.

SELECT gbx_rst_format(tile) AS format FROM rasters;
Example output
+------+
|format|
+------+
|GTiff |
+------+

rst_georeference

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_georeference(tile: Column): Column — Georeference parameters as a map.

The result is a MapType with the following keys, corresponding to GDAL's 6-element geotransform:

KeyGeotransform indexMeaning
upperLeftXGT(0)X of the upper-left corner of the upper-left pixel
upperLeftYGT(3)Y of the upper-left corner of the upper-left pixel
scaleXGT(1)Pixel width (west–east resolution)
scaleYGT(5)Pixel height (north–south resolution; often negative for north-up)
skewXGT(2)Row rotation (typically 0)
skewYGT(4)Column rotation (typically 0)

See the GDAL geotransform tutorial and raster data model for details.

SELECT gbx_rst_georeference(tile) AS georeference FROM rasters;
Example output
+-------------------------------------------------------------+
|georeference |
+-------------------------------------------------------------+
|{scaleX -> 10.0, scaleY -> -10.0, upperLeftX -> 2121950.0,...|
+-------------------------------------------------------------+

rst_getnodata

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Returns the dataset NoData value repeated once per band.

Signature: rst_getnodata(tile: Column): Column — NoData values per band.

SELECT gbx_rst_getnodata(tile) AS nodata FROM rasters;
Example output
+------+
|nodata|
+------+
|[0.0] |
+------+

rst_getsubdataset

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Subdataset availability depends on rasterio's bundled GDAL driver set.

Signature: rst_getsubdataset(tile: Column, subsetName: Column): Column — Extract subdataset.

Examples use the CMIP5 NetCDF fixture (prAdjust_day_HadGEM2-CC_*.nc) which has two subdatasets: time_bnds and prAdjust. Subdatasets require a multi-layer format such as NetCDF; plain GeoTIFFs return no subdatasets.

-- netcdf_rasters view is from the CMIP5 NetCDF fixture (has time_bnds and prAdjust)
SELECT gbx_rst_getsubdataset(tile, 'prAdjust') AS subdataset FROM netcdf_rasters;
Example output
+-----------------------------------------------------------+
|subdataset |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(the extracted prAdjust subdataset as a tile — 720x360, 31 bands)

rst_height

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_height(tile: Column): Column — Height in pixels.

SELECT gbx_rst_height(tile) AS height FROM rasters;
Example output
+------+
|height|
+------+
|161 |
+------+

rst_max

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Per-band maximum over valid (non-NoData) pixels.

Signature: rst_max(tile: Column): Column — Maximum pixel values per band.

Returns NULL for a band with zero valid pixels (all NoData) on both tiers.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands); the canonical single-band sentinel2 tile is all-NoData for this function.

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_max(tile) AS band_max FROM multiband_rasters;
Example output
+---------------------+
|band_max |
+---------------------+
|[119.0, 197.0, 148.0]|
+---------------------+

rst_median

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Per-band median over valid (non-NoData) pixels.

Signature: rst_median(tile: Column): Column — Median pixel values per band.

Returns NULL for a band with zero valid pixels (all NoData) on both tiers.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands); the canonical single-band sentinel2 tile is all-NoData for this function.

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_median(tile) AS band_median FROM multiband_rasters;
Example output
+--------------------+
|band_median |
+--------------------+
|[85.0, 157.5, 111.5]|
+--------------------+

rst_memsize

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Returns the serialized raster size in bytes.

Signature: rst_memsize(tile: Column): Column — In-memory size in bytes.

SELECT gbx_rst_memsize(tile) AS memsize FROM rasters;
Example output
+-------+
|memsize|
+-------+
|71749 |
+-------+

rst_metadata

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_metadata(tile: Column): Column — Metadata map.

SELECT gbx_rst_metadata(tile) as metadata FROM rasters;
Example output
+--------------------------------------------------+
|metadata |
+--------------------------------------------------+
|{driver -> GTiff, crs -> EPSG:32618, count -> 1,..|
+--------------------------------------------------+

rst_min

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Per-band minimum over valid (non-NoData) pixels.

Signature: rst_min(tile: Column): Column — Minimum pixel values per band.

Returns NULL for a band with zero valid pixels (all NoData) on both tiers.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands); the canonical single-band sentinel2 tile is all-NoData for this function.

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_min(tile) AS band_min FROM multiband_rasters;
Example output
+-------------------+
|band_min |
+-------------------+
|[50.0, 102.0, 82.0]|
+-------------------+

rst_numbands

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_numbands(tile: Column): Column — Number of bands.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands: red, NIR, green).

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_numbands(tile) AS num_bands FROM multiband_rasters;
Example output
+---------+
|num_bands|
+---------+
|3 |
+---------+

rst_pixelcount

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Per-band count of valid (non-NoData) pixels.

Signature: rst_pixelcount(tile: Column): Column — Total pixel count.

Examples use the multiband fixture (rgb_nir_small.tif, 8×8, 3 bands, no NoData set), yielding 64 valid pixels per band; the canonical single-band sentinel2 tile has NoData=0 with all pixels equal zero, returning [0].

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_pixelcount(tile) AS pixel_count FROM multiband_rasters;
Example output
+------------+
|pixel_count |
+------------+
|[64, 64, 64]|
+------------+

rst_pixelheight

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_pixelheight(tile: Column): Column — Pixel height in ground units.

SELECT gbx_rst_pixelheight(tile) AS pixel_height FROM rasters;
Example output
+------------+
|pixel_height|
+------------+
|10.0 |
+------------+

rst_pixelwidth

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_pixelwidth(tile: Column): Column — Pixel width in ground units.

SELECT gbx_rst_pixelwidth(tile) AS pixel_width FROM rasters;
Example output
+-----------+
|pixel_width|
+-----------+
|10.0 |
+-----------+

rst_rotation

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_rotation(tile: Column): Column — Rotation in radians.

SELECT gbx_rst_rotation(tile) AS rotation FROM rasters;
Example output
+--------+
|rotation|
+--------+
|0.0 |
+--------+

rst_scalex / rst_scaley

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_scalex(tile: Column): Column, rst_scaley(tile: Column): Column — Scale (pixel size) in X/Y.

SELECT gbx_rst_scalex(tile) AS scale_x FROM rasters;
Example output
+-------+
|scale_x|
+-------+
|10.0 |
+-------+
SELECT gbx_rst_scaley(tile) AS scale_y FROM rasters;
Example output
+-------+
|scale_y|
+-------+
|-10.0 |
+-------+

rst_skewx / rst_skewy

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_skewx(tile: Column): Column, rst_skewy(tile: Column): Column — Skew in X/Y.

SELECT gbx_rst_skewx(tile) AS skew_x FROM rasters;
Example output
+------+
|skew_x|
+------+
|0.0 |
+------+
SELECT gbx_rst_skewy(tile) AS skew_y FROM rasters;
Example output
+------+
|skew_y|
+------+
|0.0 |
+------+

rst_srid

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_srid(tile: Column): Column — the stored spatial reference ID integer (an EPSG or ESRI code), or NULL when the tile has none. Returns the code as stored; it is classified only when applied. See Coordinate Reference Systems for the SRID-vs-CRS-string model and the epsg→esri resolution rule.

SELECT gbx_rst_srid(tile) AS srid FROM rasters;
Example output
+-----+
|srid |
+-----+
|32618|
+-----+

rst_subdatasets

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Empty for single-dataset rasters (e.g. a plain GeoTIFF).

Signature: rst_subdatasets(tile: Column): Column — List of subdataset names.

Examples use the CMIP5 NetCDF fixture (prAdjust_day_HadGEM2-CC_*.nc) which has two subdatasets: time_bnds and prAdjust. Subdatasets require a multi-layer format; plain GeoTIFFs return an empty map.

-- netcdf_rasters view is from the CMIP5 NetCDF fixture (has time_bnds and prAdjust)
SELECT gbx_rst_subdatasets(tile) AS subdatasets FROM netcdf_rasters;
Example output
+------------------------------------------------------+
|subdatasets |
+------------------------------------------------------+
|{SUBDATASET_1_NAME -> ..., SUBDATASET_1_DESC -> [31...|
+------------------------------------------------------+
(map with SUBDATASET_1_NAME/DESC for time_bnds and SUBDATASET_2_NAME/DESC for prAdjust)

rst_summary

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Returns a JSON summary (driver, size, CRS, geotransform, per-band statistics); the lightweight JSON shape differs from the heavyweight gdalinfo -json output.

Signature: rst_summary(tile: Column): Column — Statistical summary of values.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands) which has real pixel data.

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_summary(tile) AS summary FROM multiband_rasters;
Example output
+------------------------------------------------------------+
|summary |
+------------------------------------------------------------+
|{"driverShortName": "GTiff", "size": [8, 8], "coordinateS...|
+------------------------------------------------------------+

rst_type

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_type(tile: Column): Column — Data type per band.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands, UInt16).

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_type(tile) AS band_types FROM multiband_rasters;
Example output
+------------------------+
|band_types |
+------------------------+
|[UInt16, UInt16, UInt16]|
+------------------------+

rst_upperleftx / rst_upperlefty

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_upperleftx(tile: Column): Column, rst_upperlefty(tile: Column): Column — Upper-left corner coordinates.

SELECT gbx_rst_upperleftx(tile) AS upper_left_x FROM rasters;
Example output
+------------+
|upper_left_x|
+------------+
|2121950.0 |
+------------+
SELECT gbx_rst_upperlefty(tile) AS upper_left_y FROM rasters;
Example output
+------------+
|upper_left_y|
+------------+
|-10790470.0 |
+------------+

rst_width

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_width(tile: Column): Column — Width in pixels.

SELECT gbx_rst_width(tile) AS width FROM rasters;
Example output
+-----+
|width|
+-----+
|236 |
+-----+

Aggregator Functions

Combine or merge rasters in group-by (7 total).

rst_bng_rasterize_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

The lightweight implementation is backed by pygx._bng cell math and rasterio. BNG cell IDs (STRING) are parsed via pygx._bng to EPSG:27700-native cell geometries and burned into the output band — the output canvas is EPSG:27700 throughout with no warp step (this aggregator takes cellid+value rows, not a raster tile).

NoData sentinel is -9999.0

Pixels not covered by any geometry in the group are set to -9999.0 (band-registered NoData). Filter or mask downstream via gbx_rst_getnodata or IS NULL on the extracted band value.

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_bng_rasterize_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_bng_rasterize_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
cell_id AS cellid,
gbx_rst_fromcontent(gbx_rst_bng_rasterize_agg(cellid, burn_value), 'GTiff') AS tile
FROM bng_cell_values
GROUP BY cell_id

Streaming aggregator that burns BNG cell geometry/value pairs (one row per cell) into a single rasterized tile per group. The input raster is automatically reprojected to EPSG:27700 (British National Grid) before rasterization. BNG cell IDs are STRING. The inverse of rst_bng_rastertogrid*: where those functions reduce raster pixels to per-cell statistics, this one synthesizes a raster from per-cell values.

Lightweight-only out_crs parameter (no-op for BNG)

The lightweight Python binding accepts an optional trailing out_crs (string CRS) argument that the heavyweight/Scala tier does not — but for BNG it is a no-op: the output is always EPSG:27700. Both out_srid and out_crs are ignored here (they exist only for signature parity with the H3/quadbin aggregators).

Signature: rst_bng_rasterize_agg(cellid: Column, value: Column, out_srid: Column, pixel_size: Column, xmin: Column, ymin: Column, xmax: Column, ymax: Column, width: Column, height: Column, mode: Column, kring_pad: Column): Column

Parameters: cellid — BNG cell ID (STRING); value — numeric burn value; out_srid — EPSG code for the output CRS (typically 27700); pixel_size — output raster cell size in metres (usually 1.0 for 1km BNG cells); xmin/ymin/xmax/ymax — output extent in EPSG:27700 metres; width/height — output raster dimensions in pixels; mode — aggregation mode for overlapping values (typically "last"); kring_pad — cell neighbourhood expansion (typically 0)

Multi-row fixture: 3 BNG 1km STRING cell rows near central London (EPSG:27700) with burn values 1.0/2.0/3.0. All tabs use the same grouped-agg rasterize invocation.

-- Rasterize BNG cells into one raster tile per region. cellid is a STRING
-- (e.g. 'TQ38SW'); the srid argument is a no-op (BNG always forces EPSG:27700,
-- pass 27700 for clarity). The extent auto-derives from the cell set (null
-- canvas args).
SELECT region_id,
gbx_rst_bng_rasterize_agg(
cellid, burn_value,
27700, cast(null as double),
cast(null as double), cast(null as double),
cast(null as double), cast(null as double),
cast(null as int), cast(null as int),
'centroids', cast(0 as int)
) AS tile
FROM bng_cell_values
GROUP BY region_id;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+---------+-----------------------------------------------------------+
|region_id|tile |
+---------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+---------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(tile, 'GTiff') to rebuild a tile struct:
+---------+---------------+
|region_id|tile |
+---------+---------------+
|... |[B@... (BINARY)|
+---------+---------------+

rst_combineavg_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Aggregate — groupBy(...).agg(rx.rst_combineavg_agg("tile")) returns the NoData-aware per-pixel mean as one tile per group; input tiles must share the same grid (shape/extent/CRS).

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_combineavg_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_combineavg_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_rst_fromcontent(gbx_rst_combineavg_agg(tile), 'GTiff') AS tile
FROM tiles
GROUP BY group_key

Signature: rst_combineavg_agg(tile: Column): Column — Average tiles per group.

Multi-tile fixture: 3 per-band rows from rgb_nir_small.tif (same grid). All tabs use the same grouped-agg invocation on multiple tile rows.

-- Group by region and average
SELECT
region,
gbx_rst_combineavg_agg(tile) as regional_average
FROM rasters
GROUP BY region;
Example output
# Heavyweight SQL — one tile struct per group:
+------+-----------------------------------------------------------+
|region|regional_average |
+------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(<agg>, 'GTiff') to rebuild a tile:
+------+----------------+
|region|regional_average|
+------+----------------+
|... |[B@... (BINARY) |
+------+----------------+

rst_derivedband_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

Powered by rasterio with GDAL VRT Python pixel functions. Aggregate — groupBy(...).agg(rx.rst_derivedband_agg("tile", pyfunc, funcName)) stacks the group's tiles as bands and applies your pixel function, returning one tile per group.

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_derivedband_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_derivedband_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_rst_fromcontent(gbx_rst_derivedband_agg(tile, 'def f(a,b): return a+b', 'f'), 'GTiff') AS tile
FROM tiles
GROUP BY group_key

Signature: rst_derivedband_agg(tile: Column, pyfunc: String, funcName: String): Column — Apply Python UDF to tiles per group.

Multi-tile fixture: 3 per-band rows from rgb_nir_small.tif. All tabs use the same grouped-agg invocation; pixel function selects band 0 (identity).

SELECT region, gbx_rst_derivedband_agg(tile, 'def f(a): return a', 'f') as result FROM rasters GROUP BY region;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+------+-----------------------------------------------------------+
|region|result |
+------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(result, 'GTiff') to rebuild a tile struct:
+------+---------------+
|region|result |
+------+---------------+
|... |[B@... (BINARY)|
+------+---------------+

rst_dtmfromgeoms_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

Powered by rasterio + SciPy (scipy.spatial.Delaunay). Aggregate — builds one TIN DTM tile per group from the group's Z-valued points via barycentric interpolation over an unconstrained Delaunay triangulation; breaklines, merge_tolerance, and snap_tolerance are accepted but not enforced (the heavyweight tier builds a constrained TIN). The lightweight Python binding also accepts an optional trailing out_crs (string CRS) argument that the SQL/heavyweight tiers do not — the heavyweight builder takes the int out_srid only. out_crs wins over out_srid when both are given. This is a lightweight superset, not a heavyweight regression.

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_dtmfromgeoms_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_dtmfromgeoms_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_rst_fromcontent(
gbx_rst_dtmfromgeoms_agg(point, null, 0.0, 0.0, 0,0,10,10, 8,8, 32633),
'GTiff'
) AS tile
FROM observations
GROUP BY group_key

Streaming aggregator that accepts one Z-valued point WKB per row and produces a TIN/Delaunay DTM raster tile per group; breaklines are supplied as a per-group constant array to enforce hard terrain edges.

Signature: rst_dtmfromgeoms_agg(point: Column, breaklines: Column, mergeTolerance: Column, snapTolerance: Column, xmin: Column, ymin: Column, xmax: Column, ymax: Column, width: Column, height: Column, out_srid: Column): Column

Parameters: point — WKB point geometry with Z coordinate (one per row); breaklines — constant WKB array of breakline geometries per group (pass null or empty array if unused); remaining parameters match rst_dtmfromgeoms

Multi-row fixture: 4 Z-valued WKB POINT rows (elevation 100–250 m) over a [0,0,1,1] EPSG:4326 extent. All tabs use the same grouped-agg invocation.

-- Stream survey points per region into one TIN DTM tile. Breaklines are a
-- per-group constant array; for 10 m cells over a 1000 m extent use 100 px.
SELECT region_id,
gbx_rst_dtmfromgeoms_agg(
point_wkb, breaklines_wkb_array,
0.0, 0.01,
bbox_xmin, bbox_ymin, bbox_xmax, bbox_ymax,
100, 100, 32633
) AS dtm
FROM survey_points
GROUP BY region_id;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+---------+-----------------------------------------------------------+
|region_id|dtm |
+---------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+---------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(dtm, 'GTiff') to rebuild a tile struct:
+---------+---------------+
|region_id|dtm |
+---------+---------------+
|... |[B@... (BINARY)|
+---------+---------------+

rst_frombands_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

Powered by rasterio. Aggregate — groupBy(...).agg(rx.rst_frombands_agg("tile", "band_index")) stacks the group's tiles into one multi-band tile ordered by ascending band_index.

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_frombands_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_frombands_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_rst_fromcontent(gbx_rst_frombands_agg(tile, band_index), 'GTiff') AS tile
FROM bands
GROUP BY group_key

Streaming aggregator that collects ordered per-band tiles (one row per band) into a single multi-band raster tile per group; use when bands arrive as separate rows rather than a pre-built array.

Signature: rst_frombands_agg(tile: Column, bandIndex: Column): Column

Parameters: tile — Single-band raster tile; bandIndex — 1-based band position within the output raster

Multi-tile fixture: 3 per-band rows from rgb_nir_small.tif with band_index 1/2/3. All tabs stack via the same grouped-agg invocation.

-- Collect per-band tiles in acquisition order into one multi-band raster per scene.
SELECT scene_id,
gbx_rst_frombands_agg(tile, band_index) AS multi_band
FROM band_tiles
GROUP BY scene_id;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+--------+-----------------------------------------------------------+
|scene_id|multi_band |
+--------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+--------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(multi_band, 'GTiff') to rebuild a tile struct:
+--------+---------------+
|scene_id|multi_band |
+--------+---------------+
|... |[B@... (BINARY)|
+--------+---------------+

rst_gridfrompoints_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

Powered by rasterio + SciPy (cKDTree IDW). Aggregate — groupBy(...).agg(rx.rst_gridfrompoints_agg(...)) inverse-distance-interpolates the group's points into one Float64 grid tile (NoData −9999). The lightweight Python binding also accepts an optional trailing out_crs (string CRS) argument that the SQL/heavyweight tiers do not — the heavyweight builder takes the int out_srid only. out_crs wins over out_srid when both are given. This is a lightweight superset, not a heavyweight regression.

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_gridfrompoints_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_gridfrompoints_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_rst_fromcontent(
gbx_rst_gridfrompoints_agg(point, value, 0,0,10,10, 8,8, 32633, 2.0, 12),
'GTiff'
) AS tile
FROM observations
GROUP BY group_key

Streaming IDW-interpolation aggregator that accepts one point geometry and one scalar value per row and produces a Float64 GeoTIFF tile per group; use when observations arrive one per row rather than as pre-built arrays.

Signature: rst_gridfrompoints_agg(point: Column, value: Column, xmin: Column, ymin: Column, xmax: Column, ymax: Column, widthPx: Column, heightPx: Column, out_srid: Column, power: Column, maxPts: Column): Column

Parameters: point — WKB point geometry (one per row); value — scalar observation for the point; xmin/ymin/xmax/ymax — output extent in CRS units (constant per group); widthPx/heightPx — output dimensions in pixels; srid — EPSG code; power — IDW distance-decay exponent (2.0 is standard); maxPts — maximum nearest neighbours considered per output pixel

Multi-row fixture: 4 WKB POINT rows with observations 10–40 over a [0,0,1,1] EPSG:4326 extent. All tabs use the same grouped-agg IDW invocation.

-- Aggregate per-station observations into one IDW tile per region.
SELECT region_id,
gbx_rst_gridfrompoints_agg(
station_wkb, observation,
bbox_xmin, bbox_ymin, bbox_xmax, bbox_ymax,
256, 256, 32633
) AS idw
FROM observations
GROUP BY region_id;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+---------+-----------------------------------------------------------+
|region_id|idw |
+---------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+---------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(idw, 'GTiff') to rebuild a tile struct:
+---------+---------------+
|region_id|idw |
+---------+---------------+
|... |[B@... (BINARY)|
+---------+---------------+

rst_h3_rasterize_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

Powered by rasterio + h3. Aggregate — groupBy(...).agg(rx.rst_h3_rasterize_agg("cellid", "value", ...)) burns each H3 cell's centroid pixel (or spatial-envelope pixels with mode='spatial_envelope') into one raster tile per group. When value is omitted or null, all burned pixels carry 1.0 (presence mask). The extent and pixel size are derived automatically from the H3 resolution unless explicit bounds are supplied; kring_pad (default 1) expands the canvas by that many rings to avoid clipping edge cells.

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_h3_rasterize_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_h3_rasterize_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
region_id AS cellid,
gbx_rst_fromcontent(
gbx_rst_h3_rasterize_agg(cellid, burn_value, 4326, null, null,null,null,null, null,null, 'centroids', 1),
'GTiff'
) AS tile
FROM h3_cell_values
GROUP BY region_id

Streaming aggregator that burns H3 cell centroid pixels (or spatial-envelope pixels) into one raster tile per group. This is the inverse of rst_h3_rastertogrid*: where those functions reduce raster pixels to per-cell statistics, rst_h3_rasterize_agg reconstructs a raster from per-cell values. Use rst_frombands_agg to stack per-threshold rasters (each produced by one rst_h3_rasterize_agg call) into a single multi-band output.

Lightweight-only out_crs parameter

The lightweight Python binding accepts an optional trailing out_crs (string CRS) argument that the heavyweight/Scala tier does not. When supplied it overrides the integer out_srid for the output CRS; the heavyweight tier accepts only the integer out_srid (its builder() is strictly 12-argument). This is a lightweight superset, not a heavyweight regression.

Worked example

The H3 Rasterize notebook walks this through end to end on a San Francisco Bay Area DEM: elevation isobands → H3 polyfill → a shared canvas from rst_h3_gridspec → per-band rst_h3_rasterize_agg → multi-band stack via rst_frombands_agg, visualized with the gbx.vizx helpers. The same pattern maps directly to a telco multi-threshold signal-coverage stack.

Signature: rst_h3_rasterize_agg(cellid: Column, value: Column, out_srid: Column, pixel_size: Column, xmin: Column, ymin: Column, xmax: Column, ymax: Column, width: Column, height: Column, mode: Column, kring_pad: Column): Column

Parameters:

  • cellid — H3 cell ID (BIGINT or STRING) to burn (one per row)
  • value — numeric burn value; pass null for a presence mask (all pixels → 1.0)
  • srid — EPSG code for the output CRS; defaults to 4326 (WGS 84)
  • pixel_size — ground resolution in CRS units (derives from H3 resolution when null)
  • xmin/ymin/xmax/ymax — output canvas extent; auto-computed from cell bounds + kring_pad when null
  • width/height — output raster dimensions in pixels; auto-derived from extent + pixel_size when null
  • mode'centroids' (default, burns the cell-centroid pixel only) or 'spatial_envelope' (burns all pixels inside the hexagon envelope)
  • kring_pad — ring count by which to expand the auto-computed canvas (default 1)

Multi-row fixture: 3 H3 resolution-9 cell rows with burn values 1.0/2.0/3.0. All tabs use the same grouped-agg rasterize invocation.

-- Rasterize H3 cells into one raster tile per region. Each cell's value is
-- burned at the cell centroid pixel.
SELECT region_id,
gbx_rst_h3_rasterize_agg(
cellid, burn_value,
4326, cast(null as double),
cast(null as double), cast(null as double),
cast(null as double), cast(null as double),
cast(null as int), cast(null as int),
'centroids', cast(1 as int)
) AS tile
FROM h3_cell_values
GROUP BY region_id;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+---------+-----------------------------------------------------------+
|region_id|tile |
+---------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+---------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(tile, 'GTiff') to rebuild a tile struct:
+---------+---------------+
|region_id|tile |
+---------+---------------+
|... |[B@... (BINARY)|
+---------+---------------+

rst_merge_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

Powered by rasterio (rasterio.merge). Aggregate — groupBy(...).agg(rx.rst_merge_agg("tile")) merges the group's tiles into one mosaic tile (output spans the union extent).

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_merge_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_merge_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_rst_fromcontent(gbx_rst_merge_agg(tile), 'GTiff') AS tile
FROM tiles
GROUP BY group_key

Signature: rst_merge_agg(tile: Column): Column — Merge tiles per group.

Multi-tile fixture: 3 per-band rows from rgb_nir_small.tif. All tabs use the same grouped-agg mosaic invocation.

SELECT
scene_id,
gbx_rst_merge_agg(tile) as merged_scene
FROM satellite_tiles
GROUP BY scene_id;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+--------+-----------------------------------------------------------+
|scene_id|merged_scene |
+--------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+--------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(merged_scene, 'GTiff') to rebuild a tile struct:
+--------+---------------+
|scene_id|merged_scene |
+--------+---------------+
|... |[B@... (BINARY)|
+--------+---------------+

rst_quadbin_rasterize_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

The lightweight implementation is backed by pygx._quadbin cell math and rasterio — it burns each quadbin cell's geometry/value into the output band via rasterio.features.rasterize, matching the heavyweight cell set and burn values exactly.

NoData sentinel is -9999.0

Pixels not covered by any geometry in the group are set to -9999.0 (band-registered NoData). Filter or mask downstream via gbx_rst_getnodata or IS NULL on the extracted band value.

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_quadbin_rasterize_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_quadbin_rasterize_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
cell_id AS cellid,
gbx_rst_fromcontent(gbx_rst_quadbin_rasterize_agg(cellid, burn_value), 'GTiff') AS tile
FROM quadbin_cell_values
GROUP BY cell_id

Streaming aggregator that burns quadbin cell geometry/value pairs (one row per cell) into a single rasterized tile per group. The input raster is interpreted as EPSG:4326 (lon/lat); resolution is the quadbin zoom level (0..26). The inverse of rst_quadbin_rastertogrid*: where those functions reduce raster pixels to per-cell statistics, this one synthesizes a raster from per-cell values.

Lightweight-only out_crs parameter

The lightweight Python binding accepts an optional trailing out_crs (string CRS) argument that the heavyweight/Scala tier does not. When supplied it overrides the integer out_srid for the output CRS; the heavyweight tier accepts only the integer out_srid (its builder() is strictly 12-argument). This is a lightweight superset, not a heavyweight regression.

Signature: rst_quadbin_rasterize_agg(cellid: Column, value: Column, out_srid: Column, pixel_size: Column, xmin: Column, ymin: Column, xmax: Column, ymax: Column, width: Column, height: Column, mode: Column, kring_pad: Column): Column

Parameters: cellid — quadbin cell ID (BIGINT); value — numeric burn value; out_srid — EPSG code for the output CRS; pixel_size — output raster cell size in the target CRS; xmin/ymin/xmax/ymax — output extent in the target CRS; width/height — output raster dimensions in pixels; mode — aggregation mode for overlapping values (typically "last"); kring_pad — cell neighbourhood expansion (typically 0)

Multi-row fixture: 3 quadbin zoom-12 cell rows near central London with burn values 1.0/2.0/3.0. All tabs use the same grouped-agg rasterize invocation.

-- Rasterize quadbin cells into one raster tile per region. Each cell's value
-- is burned at the cell centroid pixel; the extent auto-derives from the cell
-- set (null canvas args). cellid is BIGINT.
SELECT region_id,
gbx_rst_quadbin_rasterize_agg(
cellid, burn_value,
4326, cast(null as double),
cast(null as double), cast(null as double),
cast(null as double), cast(null as double),
cast(null as int), cast(null as int),
'centroids', cast(0 as int)
) AS tile
FROM quadbin_cell_values
GROUP BY region_id;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+---------+-----------------------------------------------------------+
|region_id|tile |
+---------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+---------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(tile, 'GTiff') to rebuild a tile struct:
+---------+---------------+
|region_id|tile |
+---------+---------------+
|... |[B@... (BINARY)|
+---------+---------------+

rst_rasterize_agg

LightweightHeavyweight Grouped-agg UDF
Lightweight tier (pyrx)

Powered by rasterio (rasterio.features). Aggregate — burns the group's (geom, value) rows into one tile over the given extent/size/SRID (last-wins on overlap).

Lightweight SQL returns BINARY (not the tile struct)

Heavyweight gbx_rst_rasterize_agg returns a tile STRUCT<cellid, raster, path, window, clip_polygon, clip_crs, crs, metadata> (the v2 8-field tile); the lightweight SQL function returns BINARY (the raster bytes). A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight SQL aggregate returns the raster payload as BINARY. The lightweight Python wrapper rx.rst_rasterize_agg(...) returns the full tile struct (it composes the aggregate with a tile-wrapping step), so only raw SQL differs. To rebuild the tile-struct equivalent in SQL, select the group key as cellid and wrap the BINARY with gbx_rst_fromcontent:

-- Lightweight SQL: rebuild the (cellid, raster) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_rst_fromcontent(
gbx_rst_rasterize_agg(geom, value, 0,0,10,10, 8,8, 32633),
'GTiff'
) AS tile
FROM features
GROUP BY group_key

Streaming aggregator that burns geometry/value pairs (one row per feature) into a single rasterized tile per group; use when features arrive as individual rows rather than as a pre-built collection.

Signature: rst_rasterize_agg(geom: Column, value: Column, xmin: Column, ymin: Column, xmax: Column, ymax: Column, width: Column, height: Column, out_srid: Column): Column

Parameters: geom — WKB geometry to burn; value — numeric burn value; xmin/ymin/xmax/ymax — output extent (in the target CRS); width/height — output raster dimensions in pixels; srid — EPSG code for the output CRS

Multi-row fixture: 3 polygon rows burned at values 1.0/2.0/3.0 over a [0,0,4,4] EPSG:4326 extent. All tabs use the same grouped-agg burn invocation.

-- Aggregate per-feature burn values into one rasterized tile per region.
SELECT region_id,
gbx_rst_rasterize_agg(
geom_wkb, burn_value,
bbox_xmin, bbox_ymin, bbox_xmax, bbox_ymax,
256, 256, 4326
) AS tile
FROM features
GROUP BY region_id;
Example output
# Heavyweight SQL — one v2 tile struct per group:
+---------+-----------------------------------------------------------+
|region_id|tile |
+---------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+---------+-----------------------------------------------------------+

# Lightweight SQL — raster bytes as BINARY (see the note above); wrap with
# gbx_rst_fromcontent(tile, 'GTiff') to rebuild a tile struct:
+---------+---------------+
|region_id|tile |
+---------+---------------+
|... |[B@... (BINARY)|
+---------+---------------+

Constructor Functions

Create or load rasters from path, binary content, or bands (4 total).

rst_dtmfromgeoms

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + SciPy (scipy.spatial.Delaunay). Barycentric interpolation over an unconstrained Delaunay TIN; cells outside the convex hull are NoData. breaklines, merge_tolerance, and snap_tolerance are accepted for signature parity but not enforced — the heavyweight tier builds a constrained TIN that honors them.

Create a DTM raster tile via TIN/Delaunay interpolation from an array of Z-valued point WKB geometries, with an optional array of breakline WKB geometries to preserve sharp terrain transitions.

Lightweight-only out_crs parameter

The lightweight Python binding accepts an optional trailing out_crs (string CRS) argument that the SQL and heavyweight/Scala tiers do not — the heavyweight RST_DTMFromGeoms builder is strictly ≤12-argument (…, out_srid, [no_data]) and rejects a 13th argument. In lightweight Python, out_crs (string) wins over the int out_srid. This is a lightweight superset, not a heavyweight regression.

Signature: rst_dtmfromgeoms(points_array: Column, breaklines_array: Column, merge_tolerance: Column, snap_tolerance: Column, xmin: Column, ymin: Column, xmax: Column, ymax: Column, width_px: Column, height_px: Column, out_srid: Column, [no_data: Column = null]): Column — output CRS via out_srid (int); input points assumed already in the output CRS. See Coordinate Reference Systems.

Parameters: points_array — Array of WKB point geometries with Z coordinates; breaklines_array — Array of WKB line/polygon geometries enforcing hard edges (pass null or empty array if unused); merge_tolerance/snap_tolerance — Delaunay triangulation tolerances (vertex-merge distance and snapping distance; small values such as 0.0 and 0.01 are typical); xmin/ymin/xmax/ymax — output extent in CRS units; width_px/height_px — output raster dimensions in pixels (for N-metre cells set width_px = round((xmax-xmin)/N)); out_srid — EPSG code for the output CRS. An optional trailing no_data argument overrides the default fill for cells outside the triangulated hull.

-- TIN interpolation from arrays of Z-valued point WKB and breakline WKB.
-- Output is a 100 x 100 Float64 GTiff over the extent. For N-metre cells set
-- width_px = round((xmax-xmin)/N): here a 1000 m extent at 10 m cells -> 100 px.
SELECT gbx_rst_dtmfromgeoms(
points_wkb_array, breaklines_wkb_array,
0.0, 0.01,
0.0, 0.0, 1000.0, 1000.0,
100, 100, 32633
) AS dtm
FROM survey_points;
Example output
+-----------------------------------------------------------+
|dtm |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_frombands

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Stacks an ARRAY of single-band tiles into one multi-band tile in array order (element 0 → band 1), preserving georeference/CRS/dtype/NoData from the first.

Create a raster from an array of band tiles.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_frombands(bands: Column): Column

Constructor — stacks per-band tiles into a multi-band tile. Example splits the multiband fixture into per-band tiles via rst_band, then re-stacks them into a 3-band tile.

SELECT
gbx_rst_frombands(array(band1, band2, band3)) as multi_band
FROM separated_bands;
Example output
+-----------------------------------------------------------+
|multi_band |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_fromcontent

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. The driver defaults to GTiff when unspecified and outputs are re-encoded as GeoTIFF; readable input formats are limited to the GDAL build bundled with rasterio.

Create a raster from binary content.

Signature: rst_fromcontent(content: Column, driver: Column): Column

Parameters: content — Binary column; driver — GDAL driver name

Returns: Binary raster tile data

Constructor — builds a tile from binary content. Example uses Spark's binaryFile reader to load bytes, then rst_fromcontent to decode them — this is the canonical tier-agnostic pattern (works on any compute including Serverless).

Serverless memory — you own the bytes

rst_fromcontent materializes bytes that are already in a column. Those bytes are in executor memory before this call; GeoBrix does not guard their size. On Serverless / Spark Connect the connect-aware cap is 64 MiB per tile — keep individual content values at or under that limit. For larger sources, use the virtual-tile raster readers (the default) and let the runtime page bytes lazily. See Serverless & Memory.

-- Load from binary table
SELECT
path,
gbx_rst_fromcontent(content, 'GTiff') as tile
FROM binary_raster_table;
Example output
+----+-----------------------------------------------------------+
|path|tile |
+----+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+----+-----------------------------------------------------------+

rst_fromfile

Lightweight

Reference a raster on disk as a tile, by path.

The lightweight tier returns a virtual tile by default — bytes-free, pointing at path over its whole-file window, with width/height/CRS read from the header. No pixels are read until a downstream op needs them, so this is the lazy way to load rasters by path. There is no virtualize_dir/virtualize_prefix argument here: the source file already is the durable backing store, so nothing needs writing. A path that cannot be opened returns null.

Signature: rst_fromfile(path: Column, driver: Column = 'GTiff'[, materialize: bool = False])materialize is a lightweight-Python argument; from Python, materialize=True reads the pixels now and returns a materialized tile.

Parameters: path — raster file path; driver — GDAL driver-name hint carried into metadata (rasterio auto-detects the real format on open); materialize (light Python only) — True reads pixels now and returns a materialized tile, default False returns a virtual tile.

Tier differences — virtual vs materialized

gbx_rst_fromfile is a Python UDF (requires a light-tier extra, e.g. geobrix[light_env6]; no Scala/JVM form — the executor JVM cannot read a UC Volume /Volumes/... FUSE path, whose credential is held only by Spark's managed Python worker). The SQL call is the same 2-argument form in both tiers, but the tier that registered decides the result: the lightweight registration (pyrx) returns a virtual tile, the heavyweight registration (rasterx) returns a materialized tile (JVM/heavy callers cannot use a virtual path-only tile). Whichever register() ran last wins. From Python, pass materialize=True to force bytes regardless of tier. Without a light-tier extra the function is not registered and the Python binding raises with guidance.

materialize=True errors over the Serverless cap

Calling rst_fromfile(..., materialize=True) on a file larger than the connect-aware stream cap (64 MiB on Serverless / Spark Connect, 256 MiB on classic) raises a ValueError. The error is intentional — silently materializing an oversized tile would OOM the executor. The virtual default (materialize=False, which is the lightweight default) is Serverless-safe: pixels are read lazily, size-gated, at each downstream operation. See Serverless & Memory.

-- gbx_rst_fromfile is a Python UDF (no JVM form; requires a light-tier extra, e.g. geobrix[light_env6]). The
-- SQL call is the same 2-argument form in both tiers — the tier you register
-- decides the result (whichever register() ran last wins):
-- Lightweight (rx.register / pyrx): returns a VIRTUAL tile (bytes-free,
-- path + whole-file window; lazy).
-- Heavyweight (rasterx register): returns a MATERIALIZED tile (raster
-- bytes present) — JVM/heavy callers
-- cannot use a virtual path-only tile.
SELECT
gbx_rst_fromfile('/Volumes/main/geobrix_samples/nyc/sentinel2.tif', 'GTiff') AS tile;

-- Either way, accessors read what they need — width/height come from the header
-- (no pixel read even for the virtual tile):
SELECT
path,
gbx_rst_width(gbx_rst_fromfile(path, 'GTiff')) as width,
gbx_rst_height(gbx_rst_fromfile(path, 'GTiff')) as height
FROM raster_paths;
Example output
# Both tiers return the SAME v2 tile struct (cellid, raster, path, window, ...);
# only the field values differ — virtual carries the path, materialized the bytes.

# Lightweight registration — a VIRTUAL v2 tile (raster null; path + window set):
+---------------------------------------------------------------+
|tile |
+---------------------------------------------------------------+
|{0, null, /Volumes/..., {0, 0, 10980, 10980}, ..., null, {...}}|
+---------------------------------------------------------------+

# Heavyweight registration — a MATERIALIZED v2 tile (raster bytes; path null):
+------------------------------------------------------------+
|tile |
+------------------------------------------------------------+
|{0, <raster bytes>, null, null, ..., {driver -> GTiff, ...}}|
+------------------------------------------------------------+

# width/height (either tier) read from the header:
+----+-----+------+
|path|width|height|
+----+-----+------+
|... |10980|10980 |
+----+-----+------+
Loading rasters at scale? Use the Raster Reader

rst_fromfile pulls columnar raster paths into a tile column inline. To ingest rasters as a normal Spark job — partitioned parallel reads, optional tiling (sizeInMB), FUSE-safe Volume staging — use the Raster Reader (raster_gbx / gtiff_gbx, or heavyweight gdal / gtiff_gdal): spark.read.format("raster_gbx").load(path). It, too, emits virtual tiles by default.

Have the bytes already, or need a materialized tile? Use rst_fromcontent

If you already hold raster bytes in a column (e.g. from Spark's built-in binaryFile reader), build the tile with gbx_rst_fromcontent(content, driver). Note this is not a lazy equivalent of rst_fromfile in the lightweight tier: rst_fromcontent takes bytes you have already read, so it always produces a materialized tile. (In the heavyweight tier all tiles are materialized, so there the two are interchangeable.) It also works without a light-tier extra and on any compute, since the binaryFile reader runs in Spark, which holds the Volume credential:

df = (
spark.read.format("binaryFile")
.load("/Volumes/main/geobrix_samples/geobrix-examples/nyc/*.tif")
.selectExpr("path", "gbx_rst_fromcontent(content, 'GTiff') AS tile")
)

rst_gridfrompoints

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + SciPy (cKDTree IDW). Inverse-distance interpolation (power, max_pts) to a single-band Float64 grid; NoData −9999. Matches the heavyweight invdist defaults (power=2.0, max_pts=12).

IDW-interpolate an array of Z-valued point geometries to a Float64 GeoTIFF tile covering an explicit bounding box and pixel grid. Supply the points and their scalar values as arrays in a single row; use rst_gridfrompoints_agg when points arrive one per row.

Lightweight-only out_crs parameter

The lightweight Python binding accepts an optional trailing out_crs (string CRS) argument that the SQL and heavyweight/Scala tiers do not — the heavyweight RST_GridFromPoints builder is strictly ≤11-argument (…, out_srid, [power, [max_pts]]) and rejects a 12th argument. In lightweight Python, out_crs (string) wins over the int out_srid. This is a lightweight superset, not a heavyweight regression.

Signature: rst_gridfrompoints(points_array: Column, values_array: Column, xmin: Column, ymin: Column, xmax: Column, ymax: Column, width_px: Column, height_px: Column, out_srid: Column, [power: Column, [max_pts: Column]]): Column — output CRS via out_srid (int); input points are assumed already in the output CRS. See Coordinate Reference Systems.

Parameters: points_arrayARRAY<BINARY> of WKB point geometries; values_arrayARRAY<DOUBLE> of scalar observations, one per point; xmin/ymin/xmax/ymax — output extent in CRS units; width_px/height_px — output dimensions in pixels; out_srid — EPSG code; power — IDW distance-decay exponent (2.0 is the standard); max_pts — maximum nearest neighbours considered per output pixel

-- IDW (power=2, max_points=12) from arrays of point WKB and values.
-- Output is a 256 x 256 Float64 GTiff covering the requested extent.
SELECT gbx_rst_gridfrompoints(
points_wkb_array, values_array,
0.0, 0.0, 1000.0, 1000.0,
256, 256, 32633
) AS idw
FROM point_clouds;
Example output
+-----------------------------------------------------------+
|idw |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(IDW-interpolated tile over specified extent)

Generator Functions

Produce multiple tiles or bands (7 total).

rst_bng_tessellate

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

The lightweight implementation is backed by pygx._bng cell math and rasterio. It auto-warps the input to EPSG:27700 via rasterio.warp, enumerates the overlapping BNG cells, and clips one tile per cell — rendering STRING BNG cell IDs at the row boundary and matching the heavyweight cell set and clip windows.

Tessellate a raster to British National Grid (BNG) cells — one row per overlapping cell, each clipped to that cell's extent. The raster is automatically reprojected to EPSG:27700 (British National Grid) before tessellation, so any projected or geographic input is handled transparently. Resolution accepts integer indices ±1..±6 (1 = 100 km, 2 = 10 km, 3 = 1 km, 4 = 100 m, 5 = 10 m, 6 = 1 m; negative indices address quadrant sub-cells) or string keys from BNG.resolutionMap (e.g. "1km", "100m"). Cell IDs are STRING (e.g. "TQ28", "SU3412").

Natural fit for CV image-tiling workflows that require Ordnance Survey–scale cells aligned to the national grid — for example tiling aerial or satellite imagery into 1 km BNG cells for object-detection model inference. See issue #49 for the background.

Signature: rst_bng_tessellate(tile: Column, resolution: Column): Column

SQL:

-- Heavyweight: the generator in SELECT explodes to one row per overlapping BNG
-- cell (covering mode, default; pass 'centroid' as the 3rd arg for
-- pixel-centroid single-assignment). '1km' == integer resolution 3; a raster in
-- any CRS is warped to EPSG:27700 first.
SELECT gbx_rst_bng_tessellate(tile, '1km', 'covering') FROM rasters;

-- Lightweight (pyrx): registered as a streaming table function — call with LATERAL.
SELECT t.* FROM rasters, LATERAL gbx_rst_bng_tessellate(tile, '1km', 'covering') t;
Example output
+------+------+--------------+
|source|cellid|raster |
+------+------+--------------+
|... |TQ2979|<raster bytes>|
+------+------+--------------+
(SELECT t.* expands the v2-tile struct; cellid is the BNG grid-square STRING)

rst_h3_tessellate

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Clips the raster to each overlapping H3 cell at resolution, returning one row per cell via streaming UDTF (matches the heavyweight generator behavior).

Signature: rst_h3_tessellate(tile: Column, resolution: Column, mode: Column = "covering"): Column — Tessellate raster to H3 cells. mode is "covering" (default — every overlapping cell, clipped) or "centroid" (pixel-centroid single-assignment partition). See H3 Raster Tessellation for the full mode guide.

Covering mode uses a positive-area overlap rule (shared by all three grids — rst_h3_tessellate, rst_quadbin_tessellate, rst_bng_tessellate): a cell is emitted iff its geometry has greater-than-zero area overlap with the raster. A cell that merely touches the raster along a boundary edge or corner (zero pixel overlap — common on grid-aligned tiles where the raster edges land on cell boundaries) is excluded. A within-extent cell whose pixels are all NoData is emitted — NoData renders in place, it does not punch a gap into the mosaic. This rule is identical on the lightweight and heavyweight tiers, so covering-mode cell sets match exactly across tiers.

-- Heavyweight: the generator in SELECT explodes to one row per overlapping H3
-- cell, clipped to its hexagon (covering mode, default; pass 'centroid' as the
-- 3rd arg for pixel-centroid single-assignment).
SELECT gbx_rst_h3_tessellate(tile, 7, 'covering') FROM rasters;

-- Lightweight (pyrx): registered as a streaming table function — call with LATERAL.
SELECT t.* FROM rasters, LATERAL gbx_rst_h3_tessellate(tile, 7, 'covering') t;
Example output
+------+------------------+--------------+
|source|cellid |raster |
+------+------------------+--------------+
|... |599686042433355775|<raster bytes>|
+------+------------------+--------------+

rst_maketiles

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio. Streams one tile row per subdivided region via streaming UDTF. It derives a square tile size from the MB budget and always partitions; it does not honor the heavyweight size_in_mb = -1 (single tile) or 0 (64 MB) sentinels or the power-of-four split, so tile counts and dimensions differ.

Signature: rst_maketiles(tile: Column, sizeInMB: Column): Column — Subdivide into smaller tiles by approximate size in MB.

SQL:

-- Subdivide into MB-sized tiles using LATERAL. The second argument is a target
-- size in MB, not pixel dimensions; the tile grid is derived from the MB budget.
SELECT t.*
FROM rasters,
LATERAL gbx_rst_maketiles(tile, 4) t;
Example output
+------+--------------+----+----------------------+
|cellid|raster |path|... |
+------+--------------+----+----------------------+
|0 |<raster bytes>|... |{driver -> GTiff, ...}|
+------+--------------+----+----------------------+
(one row per sub-tile; t.* expands the v2-Tile struct fields)

rst_quadbin_tessellate

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

The lightweight implementation is backed by pygx._quadbin cell math and rasterio. It enumerates the overlapping quadbin cells for the raster bbox and clips one tile per cell, matching the heavyweight cell set and clip windows.

Tessellate a raster to CARTO quadbin v0 cells — one row per overlapping cell, each clipped to that cell's extent. The input raster must be in EPSG:4326 (lon/lat); reproject upstream with rst_transform if your source CRS differs. Resolution is the quadbin zoom level (0..26). Each output row carries the quadbin cell ID (BIGINT) and the clipped tile struct.

Signature: rst_quadbin_tessellate(tile: Column, resolution: Column): Column

SQL:

-- Heavyweight: the generator in SELECT explodes to one row per overlapping
-- quadbin cell, each chip clipped to its cell (covering mode, default; pass
-- 'centroid' as the 3rd arg for pixel-centroid single-assignment). Zoom 12 for
-- a city-scale raster.
SELECT gbx_rst_quadbin_tessellate(tile, 12, 'covering') FROM rasters;

-- Lightweight (pyrx): registered as a streaming table function — call with LATERAL.
SELECT t.* FROM rasters, LATERAL gbx_rst_quadbin_tessellate(tile, 12, 'covering') t;
Example output
+------+-------------------+--------------+
|source|cellid |raster |
+------+-------------------+--------------+
|... |5250127588525215743|<raster bytes>|
+------+-------------------+--------------+
(SELECT t.* expands the v2-tile struct; cellid is the quadbin index)

rst_retile

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio. Streams one tile row per retiled region via streaming UDTF (matches the heavyweight generator behavior).

Signature: rst_retile(tile: Column, tileWidth: Column, tileHeight: Column): Column — Retile to uniform dimensions.

SQL:

SELECT t.*
FROM rasters,
LATERAL gbx_rst_retile(tile, 256, 256) t;
Example output
+------+--------------+----+----------------------+
|cellid|raster |path|... |
+------+--------------+----+----------------------+
|0 |<raster bytes>|... |{driver -> GTiff, ...}|
+------+--------------+----+----------------------+
(one row per sub-tile; t.* expands the v2-Tile struct fields)

rst_separatebands

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio. Streams one band-tile row per band via streaming UDTF — O(1) worker memory regardless of band count (matches the heavyweight generator behavior).

Signature: rst_separatebands(tile: Column): Column — Split multi-band into array of bands.

SQL:

SELECT t.*
FROM multiband_rasters,
LATERAL gbx_rst_separatebands(tile) t;
Example output
+----+-----------------------------------------------------------+-----------------------------------------------------------+-----------------------------------------------------------+
|path|red_band |green_band |blue_band |
+----+-----------------------------------------------------------+-----------------------------------------------------------+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+----+-----------------------------------------------------------+-----------------------------------------------------------+-----------------------------------------------------------+

rst_tooverlappingtiles

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio. Streams one tile row per overlapping region via streaming UDTF (matches the heavyweight generator behavior).

Signature: rst_tooverlappingtiles(tile: Column, tileWidth: Column, tileHeight: Column, overlap: Column): Column — Create overlapping tiles.

SQL:

SELECT t.*
FROM rasters,
LATERAL gbx_rst_tooverlappingtiles(tile, 256, 256, 10) t;
Example output
+------+--------------+----+----------------------+
|cellid|raster |path|... |
+------+--------------+----+----------------------+
|0 |<raster bytes>|... |{driver -> GTiff, ...}|
+------+--------------+----+----------------------+
(one row per overlapping tile; t.* expands the v2-Tile struct fields)

Grid Functions (H3)

Aggregate raster values to H3 grid cells, and utility functions for H3-based canvas setup (9 total).

gbx_h3_cell_bbox

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by h3. Returns a STRUCT<xmin DOUBLE, ymin DOUBLE, xmax DOUBLE, ymax DOUBLE> bounding box for the given H3 cell in the requested srid. In 'centroids' mode the box tightly wraps the centroid point; in 'spatial_envelope' mode it wraps the full hexagon outline. When kring_pad > 0 the k-ring of that radius is computed first and the bounding box covers all cells in the ring. The lightweight SQL function requires all four arguments explicitly; the Python API (rx.h3_cell_bbox(cellid, srid, mode, kring_pad)) honors the same defaults as the Scala implementation.

Scalar function — returns the bounding box STRUCT<xmin, ymin, xmax, ymax> for one H3 cell in the given CRS. Use this to drive the xmin/ymin/xmax/ymax and grid-size parameters of rst_h3_rasterize_agg when you need a consistent per-cell canvas, or to clip and inspect cell extents in downstream queries.

Signature: h3_cell_bbox(cellid: Column, srid: Column, mode: Column, kring_pad: Column): Column

Parameters:

  • cellid — H3 cell ID (BIGINT or STRING)
  • srid — EPSG code; 4326 for WGS 84 lon/lat
  • mode'centroids' (centroid point envelope) or 'spatial_envelope' (hexagon boundary envelope)
  • kring_pad — expand by this many k-rings before computing the bounding box; 0 = no expansion

Returns: STRUCT<xmin DOUBLE, ymin DOUBLE, xmax DOUBLE, ymax DOUBLE>

SQL:

-- Bounding box (STRUCT<xmin, ymin, xmax, ymax>) for each H3 cell in EPSG:4326.
-- Uses 'centroids' mode with no k-ring padding (kring_pad=0).
SELECT
cellid,
gbx_h3_cell_bbox(cellid, 4326, 'centroids', 0) AS bbox
FROM (
VALUES
(617733151020810239),
(617733151085035519),
(617733151021334527)
) AS t(cellid);
Example output
+------------------+------------------------------+
|cellid |bbox |
+------------------+------------------------------+
|617733151020810239|{-74.02, 40.70, -74.01, 40.71}|
+------------------+------------------------------+
(STRUCT<xmin, ymin, xmax, ymax> per H3 cell, in EPSG:4326)

rst_h3_gridspec (Python / DataFrame helper)

Lightweight (pyrx) Python helper only

rst_h3_gridspec is not registered as a SQL function and is not available in the heavyweight tier. It is a pure-Python / PySpark DataFrame helper in the pyrx package.

For the heavyweight tier, compose the equivalent shared canvas using the registered scalar gbx_h3_cell_bbox(cellid, srid, mode, kring_pad) with native Spark min/max aggregates and the same floor/ceil snap arithmetic:

SELECT min(cell_bbox.xmin), min(cell_bbox.ymin),
max(cell_bbox.xmax), max(cell_bbox.ymax)
FROM (SELECT gbx_h3_cell_bbox(cellid, 4326, 'centroids', 1) AS cell_bbox FROM cells)

rst_h3_gridspec computes the shared, snapped canvas (extent + pixel size) that a group of H3 cells should use so that per-threshold rasters align on a common grid and can be stacked via rst_frombands_agg or mosaicked via rst_merge_agg.

Signature:

rx.rst_h3_gridspec(df, cell_col="cellid", *group_cols,
srid=4326, pixel_size=None,
mode="centroids", kring_pad=1)

Typical multi-threshold workflow:

  1. Call rx.rst_h3_gridspec(df, cell_col="cellid", srid=4326, mode='centroids', kring_pad=1) once on the distinct cell set. It returns the grouped DataFrame with a grid struct column — one row per group containing the shared canvas.
  2. For each threshold band, run rst_h3_rasterize_agg with those fixed bounds — all output tiles share the same origin and pixel grid.
  3. Stack aligned bands with rst_frombands_agg (ordered by band_index), or mosaic per-cell tiles with rst_merge_agg.

Parameters:

  • df — input Spark DataFrame containing H3 cell IDs
  • cell_col — column name holding H3 cell IDs (integer or string); default "cellid"
  • *group_cols — additional grouping columns (e.g. a transmitter ID, year, month); one grid spec row is produced per group
  • srid — EPSG code for the output CRS; 4326 for WGS 84 (default)
  • pixel_size — ground resolution in CRS units; None = auto-derived from the H3 resolution via an edge-length heuristic (default)
  • mode'centroids' (default) or 'spatial_envelope'
  • kring_pad — k-ring expansion applied per cell before computing its bounding box (default 1)

Returns: the grouped DataFrame with a grid column of type:

STRUCT<xmin DOUBLE, ymin DOUBLE, xmax DOUBLE, ymax DOUBLE,
pixel_size DOUBLE, width INT, height INT, srid INT>

rst_h3_rastertogridavg

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_h3_rastertogridavg as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_h3_rastertogridavg(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridavg(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_h3_rastertogridavg(tile: Column, resolution: Column): Column

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_h3_rastertogridavg(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridavg(tile, 4) t;
Example output
+----+------------------+-------+
|band|cellID |measure|
+----+------------------+-------+
|1 |599686042433355775|123.45 |
|1 |599686043374559743|98.12 |
|2 |599686042433355775|210.67 |
+----+------------------+-------+
(one row per band×cell. The lightweight LATERAL form yields these [band, cellID,
measure] rows directly; the heavyweight scalar form returns a nested ARRAY that
explode(...) flattens to the same rows.)

rst_h3_rastertogridcount

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>, where measure is the per-cell pixel count (integer). The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_h3_rastertogridcount as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_h3_rastertogridcount(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridcount(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_h3_rastertogridcount(tile: Column, resolution: Column): Column — Pixel count per H3 cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_h3_rastertogridcount(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridcount(tile, 4) t;
Example output
+----+------------------+-------+
|band|cellID |measure|
+----+------------------+-------+
|1 |599686042433355775|256 |
|1 |599686043374559743|240 |
|2 |599686042433355775|256 |
+----+------------------+-------+
(pixel count per band×cell)

rst_h3_rastertogridmax

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_h3_rastertogridmax as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_h3_rastertogridmax(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridmax(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_h3_rastertogridmax(tile: Column, resolution: Column): Column — Max value per H3 cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_h3_rastertogridmax(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridmax(tile, 4) t;
Example output
+----+------------------+-------+
|band|cellID |measure|
+----+------------------+-------+
|1 |599686042433355775|255.0 |
|1 |599686043374559743|254.0 |
|2 |599686042433355775|240.0 |
+----+------------------+-------+
(max value per band×cell)

rst_h3_rastertogridmedian

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_h3_rastertogridmedian as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_h3_rastertogridmedian(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridmedian(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_h3_rastertogridmedian(tile: Column, resolution: Column): Column — Median value per H3 cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_h3_rastertogridmedian(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridmedian(tile, 4) t;
Example output
+----+------------------+-------+
|band|cellID |measure|
+----+------------------+-------+
|1 |599686042433355775|120.5 |
|1 |599686043374559743|122.0 |
|2 |599686042433355775|115.0 |
+----+------------------+-------+
(median value per band×cell)

rst_h3_rastertogridmin

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_h3_rastertogridmin as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_h3_rastertogridmin(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridmin(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_h3_rastertogridmin(tile: Column, resolution: Column): Column — Min value per H3 cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_h3_rastertogridmin(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridmin(tile, 4) t;
Example output
+----+------------------+-------+
|band|cellID |measure|
+----+------------------+-------+
|1 |599686042433355775|0.0 |
|1 |599686043374559743|10.0 |
|2 |599686042433355775|5.0 |
+----+------------------+-------+
(min value per band×cell)

rst_h3_rastertogridstddev

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>, where measure is the population standard deviation (sqrt of the population variance) of the valid pixel values in each cell — a single-pixel cell yields 0.0. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_h3_rastertogridstddev as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_h3_rastertogridstddev(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridstddev(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_h3_rastertogridstddev(tile: Column, resolution: Column): Column — Population standard deviation of pixel values per H3 cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_h3_rastertogridstddev(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridstddev(tile, 4) t;
Example output
+----+------------------+-------+
|band|cellID |measure|
+----+------------------+-------+
|1 |599686042433355775|35.29 |
|1 |599686043374559743|37.27 |
|2 |599686042433355775|34.01 |
+----+------------------+-------+
(standard deviation per band×cell)

rst_h3_rastertogridsum

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>, where measure is the total of the valid pixel values in each cell. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_h3_rastertogridsum as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_h3_rastertogridsum(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridsum(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_h3_rastertogridsum(tile: Column, resolution: Column): Column — Sum of pixel values per H3 cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_h3_rastertogridsum(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridsum(tile, 4) t;
Example output
+----+------------------+-------+
|band|cellID |measure|
+----+------------------+-------+
|1 |599686042433355775|31563.0|
|1 |599686043374559743|29488.0|
|2 |599686042433355775|28672.0|
+----+------------------+-------+
(sum of pixel values per band×cell)

rst_h3_rastertogridvariance

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + h3. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>, where measure is the population variance (÷ n, two-pass) of the valid pixel values in each cell — a single-pixel cell yields 0.0. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_h3_rastertogridvariance as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_h3_rastertogridvariance(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridvariance(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_h3_rastertogridvariance(tile: Column, resolution: Column): Column — Population variance of pixel values per H3 cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_h3_rastertogridvariance(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_h3_rastertogridvariance(tile, 4) t;
Example output
+----+------------------+-------+
|band|cellID |measure|
+----+------------------+-------+
|1 |599686042433355775|1245.5 |
|1 |599686043374559743|1389.2 |
|2 |599686042433355775|1156.0 |
+----+------------------+-------+
(variance per band×cell)

Grid Functions (quadbin)

Aggregate raster values to CARTO quadbin v0 grid cells (8 reducers). Each reducer returns an array (one entry per band) of struct<cellID: BIGINT, measure: DOUBLE> rows; explode the array element you want to drive per-cell rows. Resolution is the quadbin zoom (0..26). See also rst_quadbin_tessellate (Generator Functions) and rst_quadbin_rasterize_agg (Aggregator Functions) for the remaining quadbin raster-grid surface.

rst_quadbin_rastertogridavg

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + quadbin. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_quadbin_rastertogridavg as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_quadbin_rastertogridavg(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridavg(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_quadbin_rastertogridavg(tile: Column, resolution: Column): Column — Mean pixel value per quadbin cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_quadbin_rastertogridavg(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridavg(tile, 4) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |12345 |123.45 |
|1 |12346 |124.20 |
|2 |12345 |210.67 |
+----+------+-------+
(one row per band×Quadbin cell)

rst_quadbin_rastertogridcount

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + quadbin. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>, where measure is the per-cell pixel count (integer). The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_quadbin_rastertogridcount as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_quadbin_rastertogridcount(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridcount(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_quadbin_rastertogridcount(tile: Column, resolution: Column): Column — Pixel count per quadbin cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_quadbin_rastertogridcount(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridcount(tile, 4) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |12345 |256 |
|1 |12346 |240 |
|2 |12345 |256 |
+----+------+-------+
(pixel count per band×Quadbin cell)

rst_quadbin_rastertogridmax

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + quadbin. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_quadbin_rastertogridmax as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_quadbin_rastertogridmax(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridmax(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_quadbin_rastertogridmax(tile: Column, resolution: Column): Column — Max pixel value per quadbin cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_quadbin_rastertogridmax(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridmax(tile, 4) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |12345 |255.0 |
|1 |12346 |254.0 |
|2 |12345 |240.0 |
+----+------+-------+
(max value per band×Quadbin cell)

rst_quadbin_rastertogridmedian

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + quadbin. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_quadbin_rastertogridmedian as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_quadbin_rastertogridmedian(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridmedian(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_quadbin_rastertogridmedian(tile: Column, resolution: Column): Column — Median pixel value per quadbin cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_quadbin_rastertogridmedian(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridmedian(tile, 4) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |12345 |120.5 |
|1 |12346 |122.0 |
|2 |12345 |115.0 |
+----+------+-------+
(median value per band×Quadbin cell)

rst_quadbin_rastertogridmin

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + quadbin. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_quadbin_rastertogridmin as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_quadbin_rastertogridmin(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridmin(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_quadbin_rastertogridmin(tile: Column, resolution: Column): Column — Min pixel value per quadbin cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_quadbin_rastertogridmin(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridmin(tile, 4) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |12345 |0.0 |
|1 |12346 |10.0 |
|2 |12345 |5.0 |
+----+------+-------+
(min value per band×Quadbin cell)

rst_quadbin_rastertogridstddev

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + quadbin. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>, where measure is the population standard deviation (sqrt of the population variance) of the valid pixel values in each cell — a single-pixel cell yields 0.0. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_quadbin_rastertogridstddev as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_quadbin_rastertogridstddev(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridstddev(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_quadbin_rastertogridstddev(tile: Column, resolution: Column): Column — Population standard deviation of pixel values per quadbin cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_quadbin_rastertogridstddev(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridstddev(tile, 4) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |12345 |35.29 |
|1 |12346 |37.27 |
|2 |12345 |34.01 |
+----+------+-------+
(standard deviation per band×Quadbin cell)

rst_quadbin_rastertogridsum

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + quadbin. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>, where measure is the total of the valid pixel values in each cell. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_quadbin_rastertogridsum as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_quadbin_rastertogridsum(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridsum(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_quadbin_rastertogridsum(tile: Column, resolution: Column): Column — Sum of pixel values per quadbin cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_quadbin_rastertogridsum(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridsum(tile, 4) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |12345 |31563.0|
|1 |12346 |29488.0|
|2 |12345 |28672.0|
+----+------+-------+
(sum of pixel values per band×Quadbin cell)

rst_quadbin_rastertogridvariance

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio + quadbin. Returns an ARRAY (one element per band) of ARRAY<struct(cellID, measure)>, where measure is the population variance (÷ n, two-pass) of the valid pixel values in each cell — a single-pixel cell yields 0.0. The raster is interpreted as EPSG:4326 lon/lat — reproject upstream with rst_transform if your source CRS differs.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_quadbin_rastertogridvariance as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_quadbin_rastertogridvariance(tile, 4) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridvariance(tile, 4) t. Both forms appear in the SQL tab below.

Signature: rst_quadbin_rastertogridvariance(tile: Column, resolution: Column): Column — Population variance of pixel values per quadbin cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_quadbin_rastertogridvariance(tile, 4) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_quadbin_rastertogridvariance(tile, 4) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |12345 |1245.5 |
|1 |12346 |1389.2 |
|2 |12345 |1156.0 |
+----+------+-------+
(variance per band×Quadbin cell)

Grid Functions (BNG)

Aggregate raster values to British National Grid (BNG) cells (8 total). BNG functions automatically reproject the input raster to EPSG:27700 before sampling — no rst_transform needed upstream. Resolution accepts integer indices ±1..±6 (1 = 100 km, 2 = 10 km, 3 = 1 km, 4 = 100 m, 5 = 10 m, 6 = 1 m; negative indices address quadrant sub-cells) or string keys (e.g. "1km", "100m"). Cell IDs are STRING.

Lightweight tier (pyrx)

The BNG raster-grid reducers are available in both tiers. The lightweight implementation is backed by pygx._bng cell math and rasterio: it auto-warps the input to EPSG:27700 via rasterio.warp, samples pixels per cell, and renders STRING BNG cell IDs — matching the heavyweight cell set and measures exactly.

NoData and NULL

A cell that covers only NoData pixels returns NULL for the measure (not 0 or NaN) — the same behavior as the H3 and quadbin reducers. NULL is safe to filter (WHERE measure IS NULL) and is excluded by SQL aggregates like MAX/MIN/AVG.

rst_bng_rastertogridavg

LightweightHeavyweight Streaming UDTF

Mean pixel value per BNG cell. The raster is reprojected to EPSG:27700 internally before sampling.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_bng_rastertogridavg as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_bng_rastertogridavg(tile, 3) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridavg(tile, 3) t. Both forms appear in the SQL tab below.

Signature: rst_bng_rastertogridavg(tile: Column, resolution: Column): Column — Mean pixel value per BNG cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_bng_rastertogridavg(tile, 3) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridavg(tile, 3) t;
Example output
+----+------+------------------+
|band|cellID|measure |
+----+------+------------------+
|1 |OW5574|77.22222222222223 |
|1 |OW5575|80.66666666666667 |
|2 |OW5574|144.33333333333334|
+----+------+------------------+
(one row per band × BNG cell; cellID is a STRING grid-square label)

rst_bng_rastertogridcount

LightweightHeavyweight Streaming UDTF

Valid (non-NoData) pixel count per BNG cell.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_bng_rastertogridcount as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_bng_rastertogridcount(tile, 3) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridcount(tile, 3) t. Both forms appear in the SQL tab below.

Signature: rst_bng_rastertogridcount(tile: Column, resolution: Column): Column — Pixel count per BNG cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_bng_rastertogridcount(tile, 3) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridcount(tile, 3) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |OW5574|9 |
|1 |OW5575|21 |
|2 |OW5574|9 |
+----+------+-------+
(pixel count per band × BNG cell)

rst_bng_rastertogridmax

LightweightHeavyweight Streaming UDTF

Maximum pixel value per BNG cell.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_bng_rastertogridmax as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_bng_rastertogridmax(tile, 3) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridmax(tile, 3) t. Both forms appear in the SQL tab below.

Signature: rst_bng_rastertogridmax(tile: Column, resolution: Column): Column — Max pixel value per BNG cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_bng_rastertogridmax(tile, 3) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridmax(tile, 3) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |OW5574|106.0 |
|1 |OW5575|118.0 |
|1 |OW5674|107.0 |
+----+------+-------+
(max value per band × BNG cell)

rst_bng_rastertogridmedian

LightweightHeavyweight Streaming UDTF

Median pixel value per BNG cell.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_bng_rastertogridmedian as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_bng_rastertogridmedian(tile, 3) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridmedian(tile, 3) t. Both forms appear in the SQL tab below.

Signature: rst_bng_rastertogridmedian(tile: Column, resolution: Column): Column — Median pixel value per BNG cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_bng_rastertogridmedian(tile, 3) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridmedian(tile, 3) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |OW5574|88.0 |
|1 |OW5575|80.0 |
|1 |OW5674|81.0 |
+----+------+-------+
(median value per band × BNG cell)

rst_bng_rastertogridmin

LightweightHeavyweight Streaming UDTF

Minimum pixel value per BNG cell.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_bng_rastertogridmin as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_bng_rastertogridmin(tile, 3) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridmin(tile, 3) t. Both forms appear in the SQL tab below.

Signature: rst_bng_rastertogridmin(tile: Column, resolution: Column): Column — Min pixel value per BNG cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_bng_rastertogridmin(tile, 3) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridmin(tile, 3) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |OW5574|0.0 |
|1 |OW5575|54.0 |
|1 |OW5674|65.0 |
+----+------+-------+
(min value per band × BNG cell)

rst_bng_rastertogridstddev

LightweightHeavyweight Streaming UDTF

Population standard deviation (sqrt of the population variance) of pixel values per BNG cell — a single-pixel cell yields 0.0.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_bng_rastertogridstddev as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_bng_rastertogridstddev(tile, 3) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridstddev(tile, 3) t. Both forms appear in the SQL tab below.

Signature: rst_bng_rastertogridstddev(tile: Column, resolution: Column): Column — Population standard deviation of pixel values per BNG cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_bng_rastertogridstddev(tile, 3) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridstddev(tile, 3) t;
Example output
+----+------+------------------+
|band|cellID|measure |
+----+------+------------------+
|1 |OW5574|31.043975181373415|
|1 |OW5575|21.543606571950388|
|1 |OW5674|14.023789311975086|
+----+------+------------------+
(population standard deviation per band × BNG cell)

rst_bng_rastertogridsum

LightweightHeavyweight Streaming UDTF

Sum of pixel values per BNG cell.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_bng_rastertogridsum as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_bng_rastertogridsum(tile, 3) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridsum(tile, 3) t. Both forms appear in the SQL tab below.

Signature: rst_bng_rastertogridsum(tile: Column, resolution: Column): Column — Sum of pixel values per BNG cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_bng_rastertogridsum(tile, 3) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridsum(tile, 3) t;
Example output
+----+------+-------+
|band|cellID|measure|
+----+------+-------+
|1 |OW5574|695.0 |
|1 |OW5575|1694.0 |
|1 |OW5674|774.0 |
+----+------+-------+
(sum of pixel values per band × BNG cell)

rst_bng_rastertogridvariance

LightweightHeavyweight Streaming UDTF

Population variance (÷ n, two-pass) of pixel values per BNG cell — a single-pixel cell yields 0.0.

Tier differences — SQL invocation

Heavyweight registers gbx_rst_bng_rastertogridvariance as a scalar (ARRAY-returning) function — call it directly and explode(...) to flatten to rows: SELECT gbx_rst_bng_rastertogridvariance(tile, 3) AS grid FROM multiband_rasters. The lightweight (pyrx) tier registers it as a streaming table function, so lightweight SQL must use LATERAL: SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridvariance(tile, 3) t. Both forms appear in the SQL tab below.

Signature: rst_bng_rastertogridvariance(tile: Column, resolution: Column): Column — Population variance of pixel values per BNG cell.

SQL:

-- Heavyweight: scalar ARRAY return (one element per band) — call directly;
-- explode to flatten the per-band arrays to rows.
SELECT gbx_rst_bng_rastertogridvariance(tile, 3) AS grid FROM multiband_rasters;

-- Lightweight (pyrx): streaming table function — must use LATERAL.
SELECT t.* FROM multiband_rasters, LATERAL gbx_rst_bng_rastertogridvariance(tile, 3) t;
Example output
+----+------+------------------+
|band|cellID|measure |
+----+------+------------------+
|1 |OW5574|963.7283950617285 |
|1 |OW5575|464.126984126984 |
|1 |OW5674|196.66666666666666|
+----+------+------------------+
(population variance per band × BNG cell)

Operations

Transform and analyze rasters (20 total).

rst_asformat

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Output formats are limited to rasterio's bundled-GDAL writable driver set; the tile is re-encoded in the requested format.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_asformat(tile: Column, newFormat: Column): Column — Convert to another format.

-- Convert NetCDF to GeoTIFF
SELECT
path,
gbx_rst_asformat(tile, 'GTiff') as geotiff_tile
FROM netcdf_rasters;

-- Convert to PNG
SELECT
path,
gbx_rst_asformat(tile, 'PNG') as png_tile
FROM visualization_tiles;
Example output
+----+-----------------------------------------------------------+
|path|geotiff_tile |
+----+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+----+-----------------------------------------------------------+

rst_clip

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.mask). The clip geometry is assumed to be in the raster's CRS; the heavyweight tier has additional SRID-inheritance fallbacks.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_clip(tile: Column, clip: Column, cutlineAllTouched: Column, [clip_crs: Column = null]): Column — Clip by geometry. The clip argument must be WKT (string), EWKT (SRID-prefixed string), WKB (binary), or EWKB (SRID-embedded binary); do not use st_geomfromtext() or other DBR native geometry. Optional clip_crs (string, source role) declares the CRS of a plain WKB/WKT cutline — an EWKB/EWKT embedded SRID wins, absent → assumed already in the raster CRS. See Coordinate Reference Systems.

CRS handling:

  • EWKT (SRID=4326;POLYGON(...)) or EWKB (SRID encoded in the byte header) — the SRID is read, and if it differs from the raster's CRS the cutline is reprojected before clipping. Use this form whenever the geometry and raster may be in different CRSs.
  • Plain WKT / WKB (no SRID) — the geometry is assumed to already be in the raster's CRS. If that assumption is wrong (for example, lon/lat polygons against a UTM raster), the cutline will land outside the raster and you'll get an empty or blank output. Either switch to EWKT/EWKB, or reproject the geometry to the raster's CRS first.

Example clip geometry: a WKT polygon in the raster's native CRS (EPSG:32618, no SRID prefix). To clip with a WGS84 geometry use EWKT: SRID=4326;POLYGON(...) — the embedded SRID triggers auto-reprojection to the raster's CRS.

-- Clip with WKT geometry
SELECT
path,
gbx_rst_clip(
tile,
'POLYGON((-122 37, -122 38, -121 38, -121 37, -122 37))',
true
) as clipped
FROM rasters;
Example output
+----+-----------------------------------------------------------+
|path|clipped |
+----+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+----+-----------------------------------------------------------+

rst_combineavg

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Takes an ARRAY<tile> and returns the NoData-aware per-pixel mean; input tiles must share the same grid (shape/extent/CRS). cellid is preserved when all inputs share one, else −1.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_combineavg(tiles: Column): Column — Average multiple tiles (e.g. temporal composite).

SELECT gbx_rst_combineavg(array(tile)) AS combined FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|combined |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_convolve

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by SciPy (scipy.ndimage). Output is Float64 and border pixels are filled by edge-replication; the heavyweight tier preserves the input dtype and leaves border pixels unchanged.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_convolve(tile: Column, kernel: Column): Column — Apply convolution kernel.

Example kernel: 3×3 identity ([[0,0,0],[0,1,0],[0,0,0]]), which passes pixels through unchanged.

-- Apply 3x3 kernel (e.g. blur); kernel format is driver-specific
SELECT path, gbx_rst_convolve(tile, kernel) as filtered FROM rasters_with_kernels;
Example output
+----+-----------------------------------------------------------+
|path|filtered |
+----+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+----+-----------------------------------------------------------+

rst_derivedband

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio with GDAL VRT Python pixel functions. A pixel function authored for one tier runs unchanged in the other.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_derivedband(tile: Column, pyfunc: String, funcName: String): Column — Apply Python UDF to derive band.

SELECT gbx_rst_derivedband(tile, 'def double(in_ar, out_ar, xoff, yoff, xsize, ysize, raster_xsize, raster_ysize, buf_radius, gt, **kwargs):\\n    out_ar[:] = in_ar[0] * 2\\n', 'double') AS result FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|result |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_filter

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by SciPy (scipy.ndimage). The averaging filter is named 'mean' (not 'avg') and 'mode' is unavailable; the averaging output is Float32 and near-edge values may differ slightly from the heavyweight tier.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_filter(tile: Column, kernelSize: Column, operation: Column): Column — Spatial filter (e.g. median, avg).

-- Median filter (3x3 window)
SELECT
path,
gbx_rst_filter(tile, 3, 'median') as denoised
FROM noisy_rasters;

-- Average smoothing (5x5 window)
SELECT
path,
gbx_rst_filter(tile, 5, 'avg') as smoothed
FROM rasters;
Example output
+----+-----------------------------------------------------------+
|path|denoised |
+----+-----------------------------------------------------------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+----+-----------------------------------------------------------+

rst_initnodata

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. When no NoData is set it assigns -9999.0; the heavyweight tier assigns a data-type-appropriate sentinel per band, so the NoData value can differ for integer or byte rasters.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_initnodata(tile: Column): Column — Initialize NoData values.

SELECT gbx_rst_initnodata(tile) as tile FROM rasters;
Example output
+-----------------------------------------------------------+
|tile |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(tile with NoData initialized)

rst_isempty

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_isempty(tile: Column): Column — Check if raster is empty.

Returns true when the raster has no size or every band is entirely NoData.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands with real pixel data); the canonical single-band sentinel2 tile has NoData=0 with all pixels equal zero, returning true.

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_isempty(tile) AS is_empty FROM multiband_rasters;
Example output
+--------+
|is_empty|
+--------+
|false |
+--------+

rst_mapalgebra

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by NumExpr. Bands map to A, B, C, … and the calc expression is evaluated with NumExpr (no gdal_calc NumPy builtins); single-band Float32 output.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_mapalgebra(tiles: Column, expression: Column): Column — Map algebra expression (e.g. A - B).

How the inputs bind. tiles is an ARRAY<tile>. By default, band 1 of each tile, in array order, binds to the variables A, B, C, … (A = first tile, B = second, …). The result is a single-band Float32 tile on the first input's georeference.

Spec format (same on both tiers). The expression is accepted in either of two forms — identical across SQL, Scala, and both Python tiers:

  • JSON envelope (recommended; the gdal_calc spec shape): a JSON object with a calc expression — '{"calc": "A * 2"}'.
  • Bare expression string: the calc expression on its own — "A * 2".

Selecting a specific band or raster per variable (A_index / A_band). You do not need to decompose a multiband raster to do band math. The JSON envelope's per-variable keys — A_index / A_band (and B_, C_, …) — map each variable to a chosen raster (0-based, into the tiles array) and a chosen 1-based band, mirroring gdal_calc. For example, NDVI from bands 4 (NIR) and 3 (Red) of a single raster:

{"calc": "(A - B) / (A + B)", "A_index": 0, "B_index": 0, "A_band": 4, "B_band": 3}

Both A and B read raster 0 (the one tile in the array), with A = band 4 and B = band 3 — the direct equivalent of gdal_calc -A in.tif --A_band=4 -B in.tif --B_band=3 --calc="(A - B) / (A + B)". A variable with no *_index/*_band keeps the default (its ordinal raster, band 1). This works on both tiers.

The only gdal_calc envelope key the lightweight tier does not support is extra_options (raw CLI flags with no NumExpr equivalent); it raises a clear error rather than dropping it silently. The heavy tier honors extra_options as well.

Expression language differs by engine

The envelope is portable, but the calc expression language is not fully portable because each tier uses a different evaluator: the heavy tier shells out to GDAL's gdal_calc (NumPy expression syntax); the lightweight tier evaluates with NumExpr. They agree on ordinary arithmetic and comparisons (A * 2, (A - B) / (A + B), A > 0), so those expressions run unchanged on both tiers. They diverge on function spellings — e.g. gdal_calc accepts NumPy calls like numpy.where(A > 0, A, 0), whereas NumExpr wants where(A > 0, A, 0). Keep expressions to basic arithmetic for cross-tier portability. For the heavy tier's full syntax and options, see the GDAL raster calculator reference: gdal_raster_calc.

SELECT gbx_rst_mapalgebra(
array(tile),
'{"calc": "(A - B) / (A + B)", "A_index": 0, "B_index": 0, "A_band": 2, "B_band": 1}'
) AS ndvi
FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|ndvi |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_merge

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.merge). Takes an ARRAY<tile> (in one row) and mosaics them into a single tile spanning the union extent (first-tile-wins on overlap, in array order).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_merge(tiles: Column): Column — Merge tiles into mosaic.

SELECT gbx_rst_merge(array(tile)) AS merged FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|merged |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_ndvi

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Valid pixels match the heavyweight tier; pixels with a zero denominator are set to NoData (-9999) rather than left as non-finite values.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_ndvi(tile: Column, redBand: Column, nirBand: Column): Column — NDVI from band indices.

SELECT gbx_rst_ndvi(tile, 1, 2) AS ndvi FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|ndvi |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(single-band NDVI raster: (NIR-Red)/(NIR+Red))

rst_rastertoworldcoord

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_rastertoworldcoord(tile: Column, pixelX: Column, pixelY: Column): Column — Pixel to world coordinates as a struct with .x and .y fields.

SELECT
gbx_rst_rastertoworldcoord(tile, 100, 80) as world_coord,
gbx_rst_rastertoworldcoord(tile, 100, 80).x as easting,
gbx_rst_rastertoworldcoord(tile, 100, 80).y as northing
FROM rasters;
Example output
+---------------+-------+--------+
|world_coord |easting|northing|
+---------------+-------+--------+
|{500980.0, ...}|500980 |4599220 |
+---------------+-------+--------+

rst_rastertoworldcoordx / rst_rastertoworldcoordy

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_rastertoworldcoordx(tile: Column, pixelX: Column, pixelY: Column): Column, rst_rastertoworldcoordy(tile: Column, pixelX: Column, pixelY: Column): Column — World X / Y coordinate of a pixel.

SELECT
gbx_rst_rastertoworldcoordx(tile, 100, 80) as easting
FROM rasters;
Example output
+-------+
|easting|
+-------+
|500980 |
+-------+

rst_resample

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.warp).

Resample a raster tile by a multiplicative factor via gdal.Warp -r, scaling pixel dimensions up or down relative to the source.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_resample(tile: Column, factor: Column, algorithm: Column): Column

Parameters: factor — multiplicative scale factor applied to both width and height (e.g. 2.0 doubles the pixel grid); algorithm — gdalwarp resampling method name (e.g. bilinear, near, cubic, cubicspline, lanczos, average)

Esri Resample / changing cell size

The rst_resample* family is GeoBrix's equivalent of the ArcGIS Resample tool — producing a new raster at a different cell size with a chosen resampling method (algorithm: near, bilinear, cubic, cubicspline, lanczos, average). Pick the variant by how you specify the target:

  • rst_resample — by a multiplicative factor (e.g. 2.0 doubles the grid).
  • rst_resample_to_res — by target ground resolution in CRS units (e.g. metres per pixel).
  • rst_resample_to_size — by target pixel dimensions (width × height).

Unlike rst_sample — which reads a value at a point and is nearest-pixel only — resampling rewrites the whole grid. So to sample with bilinear or cubic interpolation, resample first with the desired algorithm, then call rst_sample.

See Raster Sampling for the full workflow guide.

SQL:

-- Upsample 2x with bilinear interpolation. Output dims = source dims * 2.
SELECT gbx_rst_resample(tile, 2.0, 'bilinear') AS upsampled FROM rasters;
Example output
+-----------------------------------------------------------+
|upsampled |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_resample_to_res

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.warp).

Resample a raster tile to an explicit ground resolution in CRS units via gdal.Warp -tr.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_resample_to_res(tile: Column, xRes: Column, yRes: Column, algorithm: Column): Column

Parameters: xRes — target pixel width in CRS units (e.g. metres for a metric projection); yRes — target pixel height in CRS units; algorithm — gdalwarp resampling method name (e.g. average, bilinear, near)

Part of the rst_resample* family — see the Esri Resample note for how it relates to the ArcGIS Resample tool and rst_sample.

SQL:

-- Downsample to a 100 m grid (metric CRS). 'average' weights cells by area.
SELECT gbx_rst_resample_to_res(tile, 100.0, 100.0, 'average') AS coarse
FROM rasters;
Example output
+-----------------------------------------------------------+
|coarse |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_resample_to_size

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.warp).

Resample a raster tile to an explicit pixel grid size via gdal.Warp -ts.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_resample_to_size(tile: Column, widthPx: Column, heightPx: Column, algorithm: Column): Column

Parameters: widthPx — target output width in pixels; heightPx — target output height in pixels; algorithm — gdalwarp resampling method name (e.g. near for categorical rasters, bilinear for continuous)

Part of the rst_resample* family — see the Esri Resample note for how it relates to the ArcGIS Resample tool and rst_sample.

SQL:

-- Force a 512 x 512 tile, near-neighbour for categorical rasters.
SELECT gbx_rst_resample_to_size(tile, 512, 512, 'near') AS sized FROM rasters;
Example output
+-----------------------------------------------------------+
|sized |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_transform

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.warp). Reprojection uses the GDAL build bundled with rasterio, whose projection database and driver set may be narrower than the heavyweight tier.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_transform(tile: Column, targetSrid: Column): Column — Reproject to a target SRID (a positive EPSG or ESRI code, classified at apply time); 0 or a code in neither registry is rejected with a clear error. Use rst_transformcrs to reproject to a target given as a CRS string. See Coordinate Reference Systems.

-- Reproject to WGS84
SELECT
path,
gbx_rst_transform(tile, 4326) as wgs84_tile,
gbx_rst_srid(gbx_rst_transform(tile, 4326)) as new_srid
FROM rasters;

-- Reproject and clip
SELECT
path,
gbx_rst_clip(gbx_rst_transform(tile, 4326), boundary, true) as result
FROM rasters;
Example output
+----+-----------------------------------------------------------+--------+
|path|wgs84_tile |new_srid|
+----+-----------------------------------------------------------+--------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|4326 |
+----+-----------------------------------------------------------+--------+

rst_transformcrs

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.warp) + pyproj. Reprojection uses the GDAL build bundled with rasterio, whose projection database and driver set may be narrower than the heavyweight tier.

Signature: rst_transformcrs(tile: Column, targetCrs: Column): Column — reproject to a target CRS given as a string (EPSG:x / ESRI:x / WKT / PROJ4; an int-castable string is treated as a SRID). See Coordinate Reference Systems.

Distinct from rst_transform (integer EPSG only): rst_transformcrs accepts any CRS string — an authority code (EPSG:3857, ESRI:54008), WKT, or PROJ4 — so you can reproject to a non-EPSG target. An int-castable string ('3857') is treated as an EPSG SRID. See the CRS: SRID int vs CRS string note above.

-- Reproject to Web Mercator using a CRS string.
-- Unlike rst_transform (int EPSG only), rst_transformcrs also accepts
-- ESRI codes, WKT, or PROJ4 targets. An int-castable string ('3857')
-- is treated as an EPSG SRID.
SELECT
path,
gbx_rst_transformcrs(tile, 'EPSG:3857') as webmercator_tile,
gbx_rst_crs(gbx_rst_transformcrs(tile, 'EPSG:3857')) as new_crs
FROM rasters;
Example output
+----+-----------------------------------------------------------+---------+
|path|webmercator_tile |new_crs |
+----+-----------------------------------------------------------+---------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|EPSG:3857|
+----+-----------------------------------------------------------+---------+

rst_tryopen

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_tryopen(tile: Column): Column — Validate raster can be opened.

Examples use the multiband fixture (rgb_nir_small.tif, committed to the repo, always openable).

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_tryopen(tile) AS try_open FROM multiband_rasters;
Example output
+--------+
|try_open|
+--------+
|true |
+--------+

rst_updatetype

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Output is re-encoded as GeoTIFF; a NoData value that is not representable in the target type is dropped.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_updatetype(tile: Column, newType: Column): Column — Convert raster data type.

SELECT gbx_rst_updatetype(tile, 'Float32') as float_tile FROM rasters;
Example output
+-----------------------------------------------------------+
|float_tile |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_worldtorastercoord

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_worldtorastercoord(tile: Column, worldX: Column, worldY: Column): Column — World to pixel coordinates as a struct with .x and .y fields.

-- Find pixel coordinates for a specific location (center of raster)
SELECT
gbx_rst_worldtorastercoord(tile, 2122955.0, -10791275.0) as pixel_coord,
gbx_rst_worldtorastercoord(tile, 2122955.0, -10791275.0).x as pixel_col,
gbx_rst_worldtorastercoord(tile, 2122955.0, -10791275.0).y as pixel_row
FROM rasters;
Example output
+-----------+---------+---------+
|pixel_coord|pixel_col|pixel_row|
+-----------+---------+---------+
|{5490, ...}|5490 |5490 |
+-----------+---------+---------+

rst_worldtorastercoordx / rst_worldtorastercoordy

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Signature: rst_worldtorastercoordx(tile: Column, worldX: Column, worldY: Column): Column, rst_worldtorastercoordy(tile: Column, worldX: Column, worldY: Column): Column — Pixel column / row for a world coordinate.

SELECT
gbx_rst_worldtorastercoordx(tile, 2122955.0, -10791275.0) as pixel_col
FROM rasters;
Example output
+---------+
|pixel_col|
+---------+
|5490 |
+---------+

Web-Mercator Tile Output

Reproject rasters to EPSG:3857 (Web Mercator) and emit slippy-map XYZ tiles. Pair with gbx_pmtiles_agg or the PMTiles writer to publish a raster pyramid as a single .pmtiles archive. See the Helios notebooks for a worked example: NAIP aerial scenes are reprojected and pyramided into a PMTiles archive in NB02.

rst_tilexyz

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rio-tiler + morecantile. Out-of-extent tiles return a transparent PNG (never null); available output formats depend on rasterio's bundled GDAL build.

Signature: rst_tilexyz(tile: Column, z: Column, x: Column, y: Column, format: Column, tileSize: Column, resampling: Column): Column — Render a single web-mercator XYZ tile from a raster as encoded image bytes (e.g. PNG, JPEG, WebP) at the given tile coordinates and pixel size.

Display RGB(A) output (both tiers)

The output is a display web-map tile, not the source's raw bands. PNG and WebP are RGBA (4-band); JPEG is RGB (3-band, no alpha). The alpha channel is a binary transparency mask derived from the source's valid-data footprint, so a pixel that is NoData — whether outside the raster or an internal hole — renders transparent, and both the lightweight and heavyweight tiers agree on which pixels are transparent. Band mapping matches the lightweight tier: a single-band source becomes greyscale RGB (R=G=B), a two-band source uses band 1 as greyscale RGB and band 2 as the alpha channel, three bands map to R, G, B, an existing fourth band is treated as alpha, and five-or-more-band sources use the first three bands as RGB. Non-8-bit sources are contrast-rescaled to 8-bit per the rescale argument (default "auto"; see the rescale note above). WebP alpha requires GDAL WebP-alpha support in the runtime; where absent, WebP falls back to RGB.

-- Render tile (z=10, x=512, y=512) as 256x256 PNG bytes.
-- rescale='auto' (default) rescales non-8-bit imagery by whole-dataset min/max
-- for display contrast; 'none' keeps the raw full-dtype-range mapping; a
-- 'min,max' string sets explicit bounds.
SELECT
path,
gbx_rst_tilexyz(tile, 10, 512, 512, 'PNG', 256, 'bilinear', 'auto') as tile_png
FROM rasters;
Example output
+----+--------+
|path|tile_png|
+----+--------+
|... |[BINARY]|
+----+--------+

rst_to_webmercator

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.warp). Uses rasterio's bundled GDAL build, whose projection and driver coverage may be narrower than the heavyweight tier.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_to_webmercator(tile: Column): Column — Reproject a raster to EPSG:3857 (Web Mercator) using bilinear resampling by default. The returned tile carries srid = 3857.

-- Reproject to web mercator before slippy-map tiling (default bilinear resampling).
SELECT
path,
gbx_rst_to_webmercator(tile) as web_tile,
gbx_rst_srid(gbx_rst_to_webmercator(tile)) as new_srid
FROM rasters;
Example output
+----+-----------------------------------------------------------+--------+
|path|web_tile |new_srid|
+----+-----------------------------------------------------------+--------+
|... |{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|3857 |
+----+-----------------------------------------------------------+--------+

rst_xyzpyramid

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rio-tiler + morecantile. Streams one XYZ tile row per intersecting tile via streaming UDTF. Bounded by max_z <= 20 and at most 1,000,000 candidate tiles.

Signature: rst_xyzpyramid(tile: Column, minZoom: Column, maxZoom: Column): Column — Generator: explode a raster into one row per intersecting (z, x, y) tile across a zoom range, producing PNG bytes per tile. Use LATERAL VIEW to materialize the rows; the output struct exposes z, x, y, and bytes. Each tile is rendered by rst_tilexyz, so the per-tile PNG is display RGBA with the same band mapping and binary NoData alpha described above.

-- Explode a raster into per-tile rows across zoom levels 4..6 (PNG, 256px).
-- Optional trailing rescale arg (default 'auto') controls 8-bit display contrast:
-- gbx_rst_xyzpyramid(tile, 4, 6, 'PNG', 256, 'bilinear', 'auto')
SELECT
path,
t.tile.z as z,
t.tile.x as x,
t.tile.y as y,
t.tile.bytes as png_bytes
FROM rasters
LATERAL VIEW gbx_rst_xyzpyramid(tile, 4, 6) AS t;
Example output
+----+-+-+-+---------+
|path|z|x|y|png_bytes|
+----+-+-+-+---------+
|... |4|5|6|[BINARY] |
+----+-+-+-+---------+

Vector↔raster bridge

Move data between the raster (tile) and vector (geom) worlds.

rst_polygonize

LightweightHeavyweight Streaming UDTF
Lightweight tier (pyrx)

Powered by rasterio (rasterio.features).

Tier differences — SQL invocation

Heavyweight registers gbx_rst_polygonize as a scalar (ARRAY-returning) function — call it directly: SELECT gbx_rst_polygonize(tile, band, connectedness) AS features FROM <table>, where each array element is a struct(geom_wkb, value). The lightweight (pyrx) tier registers it as a streaming Python table function, so lightweight SQL must use LATERAL — which also streams polygon rows without buffering (avoids OOM on rasters with unbounded polygon fan-out): SELECT t.geom_wkb, t.value FROM <table>, LATERAL gbx_rst_polygonize(tile, band, connectedness) t. Both forms appear in the SQL tab below.

Signature (heavyweight): rst_polygonize(tile: Column, band: Column, connectedness: Column): Column — Trace contiguous-value regions of a tile into an array of features. Each feature carries the source pixel value as the value field.

SQL:

-- Heavyweight: scalar ARRAY return — call directly; each feature carries the
-- source pixel value as the `value` field. Round-trip: rasterize a polygon then
-- immediately polygonize it.
SELECT gbx_rst_polygonize(
gbx_rst_rasterize(
unhex('010300000001000000050000000000000000000000000000000000000000000000000024400000000000000000000000000000244000000000000024400000000000000000000000000000244000000000000000000000000000000000'),
42.0, 0.0, 0.0, 10.0, 10.0, 100, 100, 4326
)
) AS features;

-- Lightweight (pyrx): streaming table function — must use LATERAL; one row per
-- contiguous-value region as (geom_wkb, value).
SELECT t.geom_wkb, t.value FROM rasters, LATERAL gbx_rst_polygonize(tile, 1, 4) t;
Example output
# Heavyweight SQL — one ARRAY of features per row:
+------------------+
|features |
+------------------+
|[{[BINARY], 42.0}]|
+------------------+

# Lightweight SQL — LATERAL streams one row per region (geom_wkb, value):
+--------+-----+
|geom_wkb|value|
+--------+-----+
|... |365.0|
+--------+-----+

rst_rasterize

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.features).

Lightweight-only out_crs parameter

The lightweight Python binding accepts an optional trailing out_crs (string CRS) argument that the SQL and heavyweight/Scala tiers do not — the heavyweight RST_Rasterize builder is strictly 9-argument (out_srid only) and rejects a 10th argument. In lightweight Python, out_crs (string) wins over the int out_srid; both → error; neither → the geometry's carried source CRS. This is a lightweight superset, not a heavyweight regression.

Signature: rst_rasterize(geom: Column, burnValue: Column, xMin: Column, yMin: Column, xMax: Column, yMax: Column, width: Column, height: Column, [out_srid: Column = null]): Column — Burn a polygon (WKB) into a fresh GeoTIFF tile at the given extent and pixel dimensions. Pixels inside the polygon carry burnValue; pixels outside are NoData. The output CRS is out_srid (integer EPSG code); the geometry is reprojected from its source CRS into the output CRS before burning. When out_srid is omitted the geometry's carried source CRS is used. See Coordinate Reference Systems.

SQL:

-- WKB hex below is POLYGON((0 0, 10 0, 10 10, 0 10, 0 0)). The output `tile`
-- is a GTiff-backed raster at the given extent and resolution; pixels inside
-- the polygon carry the burn value (42.0), pixels outside are NoData.
SELECT gbx_rst_rasterize(
unhex('010300000001000000050000000000000000000000000000000000000000000000000024400000000000000000000000000000244000000000000024400000000000000000000000000000244000000000000000000000000000000000'),
42.0, 0.0, 0.0, 10.0, 10.0, 100, 100, 4326
) AS tile;
Example output
+-----------------------------------------------------------+
|tile |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(rasterized tile: pixels inside the polygon carry the burn value; outside = NoData)

Terrain Analysis

Thin wrappers around gdal.DEMProcessing for digital elevation model (DEM) derivatives. Each function takes a single-band DEM tile and returns a derived tile of the same footprint. See the Helios notebooks for a worked example: gbx_rst_slope, gbx_rst_aspect, and gbx_rst_hillshade are applied to 3DEP DEMs in NB03 to produce terrain layers and a per-H3-cell solar score.

rst_aspect

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by NumPy — a reimplementation of GDAL gdaldem; results are close but not bit-identical to the heavyweight tier (edge pixels are filled and NoData is not excluded from the 3×3 window).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_aspect(tile: Column, trigonometric: Column, zeroForFlat: Column): Column — Compass direction of steepest descent in degrees (0=N, 90=E, 180=S, 270=W). Flat areas return -9999 unless zeroForFlat = true. Set trigonometric = true for mathematical convention (0=E, counter-clockwise).

-- Aspect in compass degrees (0=N, 90=E, 180=S, 270=W). Flat areas get -9999
-- unless zero_for_flat=true.
SELECT gbx_rst_aspect(tile, false, false) AS aspect FROM dem_rasters;
Example output
+-----------------------------------------------------------+
|aspect |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(aspect in compass degrees: 0=N, 90=E, 180=S, 270=W)

rst_color_relief

LightweightHeavyweight
Cross-tier output differs (both tiers, by design)

The two tiers use different color interpolation engines, so their pixel values are close but not identical and are not byte-comparable: the heavyweight tier calls GDAL gdal.DEMProcessing color-relief (GDAL's native C interpolation), while the lightweight (pyrx) tier is a NumPy reimplementation using per-channel np.interp. Two known differences on the lightweight tier: the gdaldem default color keyword is not supported (it is skipped; out-of-range elevations are clamped to the nearest color stop by np.interp instead), and boundary/edge interpolation may differ slightly. Both tiers emit an RGB or RGBA Byte tile (RGBA when any color-table entry carries an alpha column). Because the outputs diverge, this function is not cross-tier fingerprint-compared in benchmarks (measured timing-only); pick the tier by your pipeline (heavyweight for gdaldem-exact output, lightweight for the pure-Python/Serverless path).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_color_relief(tile: Column, colorTablePath: Column): Column — Apply a gdaldem color table (elevation R G B [A] per line) to produce an RGB(A) visualization tile. Special values nv (NoData color), 0%, and 100% (percentages of the band value range) are honored on both tiers; the default keyword is honored only on the heavyweight tier (see the tier note above).

-- Map elevation values to RGBA colors via a gdaldem color table.
SELECT gbx_rst_color_relief(tile, '{COLOR_TABLE_PATH}') AS rgba
FROM dem_rasters;
Example output
+-----------------------------------------------------------+
|rgba |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(4-band RGBA tile mapped via gdaldem color table)

rst_hillshade

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by NumPy — a reimplementation of GDAL gdaldem; results are close but not bit-identical to the heavyweight tier (edge pixels are filled and NoData is not excluded from the 3×3 window).

Lightweight-only xscale / yscale parameters

The lightweight Python binding accepts two optional horizontal-scale overrides — xscale and yscale — that the SQL and heavyweight/Scala tiers do not (the heavyweight RST_Hillshade builder is strictly 4-argument: tile, azimuth, altitude, z_factor). By default the horizontal scale is auto-derived from the CRS; pass both xscale and yscale to override it. This is a lightweight superset, not a heavyweight regression.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_hillshade(tile: Column, azimuth: Column, altitude: Column, zFactor: Column): Column — 8-bit (0..255) shaded relief image. Common values: NW sun azimuth 315.0, altitude 45.0, zFactor = 1.0.

-- 8-bit (0..255) hillshade: NW sun, 45-deg altitude, default z-factor.
SELECT gbx_rst_hillshade(tile, 315.0, 45.0, 1.0) AS hillshade FROM dem_rasters;
Example output
+-----------------------------------------------------------+
|hillshade |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(8-bit hillshade: 0..255, NW azimuth 45-degree altitude)

rst_roughness

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by NumPy — a reimplementation of GDAL gdaldem; results are close but not bit-identical to the heavyweight tier (edge pixels are filled and NoData is not excluded from the 3×3 window).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_roughness(tile: Column): Column — Largest absolute difference between a pixel and any of its 8 neighbours in a 3×3 window.

-- Roughness: max absolute neighbour difference in a 3x3 window.
SELECT gbx_rst_roughness(tile) AS roughness FROM dem_rasters;
Example output
+-----------------------------------------------------------+
|roughness |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(roughness: max absolute difference in 3x3 window)

rst_slope

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by NumPy — a reimplementation of GDAL gdaldem. Results are close but not bit-identical: edge pixels are filled by replicating the border (gdaldem leaves them NoData) and NoData cells are not excluded from the 3×3 window.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_slope(tile: Column, unit: Column, xscale: Column, yscale: Column): Column — Compute slope per pixel. unit is 'degrees' or 'percent'; xscale and yscale are the elevation/horizontal unit ratio per axis (supply both or neither; when omitted, GDAL 3.11+ auto-derives from the raster CRS). For isotropic scaling pass the same value to both (e.g. 1.0, 1.0 for a projected CRS in metres).

-- Slope in degrees per pixel (auto-scale from CRS). Use unit='percent' for rise/run.
-- Pass xscale and yscale together to override the horizontal scale per axis.
SELECT gbx_rst_slope(tile, 'degrees', 1.0, 1.0) AS slope FROM dem_rasters;
Example output
+-----------------------------------------------------------+
|slope |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(slope in degrees; auto-scaled from raster CRS units)

rst_tpi

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by NumPy — a reimplementation of GDAL gdaldem; results are close but not bit-identical to the heavyweight tier (edge pixels are filled and NoData is not excluded from the 3×3 window).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_tpi(tile: Column): Column — Topographic Position Index — pixel value minus the mean of its 8 neighbours. Positive values are ridges, negative values are valleys.

-- TPI: difference from neighbour-mean; +ve = ridge, -ve = valley.
SELECT gbx_rst_tpi(tile) AS tpi FROM dem_rasters;
Example output
+-----------------------------------------------------------+
|tpi |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(TPI: positive=ridge, negative=valley)

rst_tri

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by NumPy — a reimplementation of GDAL gdaldem; results are close but not bit-identical to the heavyweight tier (edge pixels are filled and NoData is not excluded from the 3×3 window).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_tri(tile: Column): Column — Terrain Ruggedness Index — mean absolute difference between a pixel and its 8 neighbours. Useful for landscape-ecology habitat scoring.

-- TRI: mean absolute neighbour difference; useful for landscape ecology.
SELECT gbx_rst_tri(tile) AS tri FROM dem_rasters;
Example output
+-----------------------------------------------------------+
|tri |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(TRI: mean absolute neighbour difference)

Spectral Indices

Multi-band satellite math built on gbx_rst_mapalgebra. Band arguments are 1-based GDAL band indices; the output is always a single-band Float32 GeoTIFF tile. gbx_rst_ndvi is documented under Operations.

rst_evi

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Valid pixels match the heavyweight tier; pixels with a zero denominator are set to NoData (-9999) rather than left as non-finite values.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_evi(tile: Column, redBand: Column, nirBand: Column, blueBand: Column): Column — Enhanced Vegetation Index. Formula: G * (NIR - Red) / (NIR + C1*Red - C2*Blue + L) with MODIS canonical coefficients G=2.5, L=1.0, C1=6.0, C2=7.5.

SELECT gbx_rst_evi(tile, 1, 2, 3) AS evi FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|evi |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(single-band EVI raster: G*(NIR-Red)/(NIR+C1*Red-C2*Blue+L))

rst_index

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumExpr. Generic named-index dispatcher over a band_map; single-band Float32. Zero-denominator pixels are set to NoData (−9999).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_index(tile: Column, indexName: Column, bandMap: Column): Column — Generic dispatcher that picks a built-in formula by name and wires bands via a MAP<STRING, INT> (e.g. map('red', 1, 'nir', 2)). Built-in names: ndvi, gndvi, msavi, ndvi_re, ndmi, ndsi.

SELECT gbx_rst_index(tile, 'ndvi', map('red', 1, 'nir', 2)) AS ndvi FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|ndvi |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(single-band index raster computed from named formula)

rst_nbr

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Valid pixels match the heavyweight tier; pixels with a zero denominator are set to NoData (-9999) rather than left as non-finite values.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_nbr(tile: Column, nirBand: Column, swirBand: Column): Column — Normalized Burn Ratio. Formula: (NIR - SWIR) / (NIR + SWIR). The pre-/post-fire difference (dNBR) is the canonical burn-severity index.

SELECT gbx_rst_nbr(tile, 2, 3) AS nbr FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|nbr |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(single-band NBR raster: (NIR-SWIR)/(NIR+SWIR))

rst_ndwi

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Valid pixels match the heavyweight tier; pixels with a zero denominator are set to NoData (-9999) rather than left as non-finite values.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_ndwi(tile: Column, greenBand: Column, nirBand: Column): Column — Normalized Difference Water Index (McFeeters 1996). Formula: (Green - NIR) / (Green + NIR). Positive values typically indicate open water.

SELECT gbx_rst_ndwi(tile, 3, 2) AS ndwi FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|ndwi |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(single-band NDWI raster: (Green-NIR)/(Green+NIR))

rst_savi

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Valid pixels match the heavyweight tier; pixels with a zero denominator are set to NoData (-9999) rather than left as non-finite values.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_savi(tile: Column, redBand: Column, nirBand: Column, l: Column): Column — Soil-Adjusted Vegetation Index. Formula: (NIR - Red) / (NIR + Red + L) * (1 + L). L = 0.5 (the canonical default) is a balanced soil/vegetation tradeoff; L = 0 reduces SAVI to NDVI.

SELECT gbx_rst_savi(tile, 1, 2, 0.5) AS savi FROM multiband_rasters;
Example output
+-----------------------------------------------------------+
|savi |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(single-band SAVI raster: (NIR-Red)/(NIR+Red+L)*(1+L))

Pixel ops + extraction

Per-pixel transformations and band-level extraction.

rst_band

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_band(tile: Column, bandIndex: Column): Column — Extract a single band from a multi-band raster as a new single-band tile (gdal.Translate -b N). 1-based band index.

Example uses the multiband fixture (rgb_nir_small.tif, 3 bands) to demonstrate extraction; result has num_bands = 1.

-- Pull band 1 (1-based) as a fresh single-band tile.
SELECT gbx_rst_band(tile, 1) AS b1 FROM rasters;
Example output
+-----------------------------------------------------------+
|b1 |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_buildoverviews

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Builds internal GeoTIFF overviews.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_buildoverviews(tile: Column, levels: Column, [resampling: Column = lit("average")]): Column — Add pyramid overview levels to a tile via ds.BuildOverviews. levels is an ARRAY<INT> (e.g. array(2, 4, 8, 16)); resampling is one of nearest, average, gauss, cubic, cubicspline, lanczos, bilinear, mode.

-- Add 2x / 4x overviews to the tile via the 'average' resampling.
SELECT gbx_rst_buildoverviews(tile, array(2, 4), 'average') AS withovr
FROM rasters;
Example output
+-----------------------------------------------------------+
|withovr |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_fillnodata

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio (rasterio.fill).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_fillnodata(tile: Column, [maxSearchDist: Column = lit(100), smoothingIter: Column = lit(0)]): Column — Fill NoData pixels via gdal.FillNodata using inverse-distance interpolation from neighbors within maxSearchDist pixels. smoothingIter applies an optional post-fill 3×3 smoothing pass.

-- Fill NoData holes searching up to 100 pixels in each direction.
SELECT gbx_rst_fillnodata(tile, 100.0, 0) AS filled FROM rasters;
Example output
+-----------------------------------------------------------+
|filled |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_histogram

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + NumPy. Per-band bucket counts via numpy.histogram; map keys are band_<i> (1-based).

Signature: rst_histogram(tile: Column, [bands: Column = null, nBuckets: Column = lit(256), min: Column = null, max: Column = null, includeNodata: Column = lit(false)]): Column — Compute per-band histograms via band.GetHistogram. Returns MAP<STRING, ARRAY<LONG>> keyed by "band_<n>" with bucket counts. If bands is null, all bands are processed; if min / max are null, GDAL auto-detects the range.

Examples use the multiband fixture (rgb_nir_small.tif, 3 bands) so the histogram has entries for each band.

-- multiband_rasters view is from rgb_nir_small.tif (3 bands: red, NIR, green)
SELECT gbx_rst_histogram(tile) AS histogram FROM multiband_rasters;
Example output
+-------------------------------------------------+
|histogram |
+-------------------------------------------------+
|{band_1 -> [1, 0, 0, ...], band_2 -> [1, 0, 1,...|
+-------------------------------------------------+

rst_sample

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Point geometries only; the point is assumed to be in the raster's CRS.

Signature: rst_sample(tile: Column, geom: Column, [crs: Column = null]): Column — Sample the raster at the geometry's location(s). For a POINT, returns ARRAY<DOUBLE> of one value per band at the nearest pixel. The point is reprojected from its source CRS to the raster CRS: an EWKB/EWKT embedded SRID wins, else the optional crs (string, source role), else assumed already aligned. See Coordinate Reference Systems.

Esri RS_VALUE / raster sampling

rst_sample is GeoBrix's equivalent of the ArcGIS Sample tool's RS_VALUE — reading a raster's cell value at a point. It returns ARRAY<DOUBLE> (one value per band, in band order), or null where the point falls outside the raster (the NoData/out-of-extent case). Sampling is nearest-pixel; for bilinear or cubic, run rst_resample first, then sample.

  • Multiple rasters (Esri's RS_VALUE1, RS_VALUE2, …): call rst_sample once per raster and alias each result column.
  • A points table against a raster tile set (the Sample-tool workflow at scale): join the points to the tiles that contain them — with st_intersects, or a raster grid tessellation such as rst_h3_tessellate for an index join — then call rst_sample(tile, point) per row.

See Raster Sampling for the full workflow guide.

-- Sample the DEM at a point in its native CRS (EPSG:32618). Tagging the point
-- with an SRID (EWKT `SRID=32618;...`) lets gbx_rst_sample land it correctly.
SELECT gbx_rst_sample(tile, 'SRID=32618;POINT(500320 4500320)') AS values FROM dem_rasters;
Example output
+-------+
|values |
+-------+
|[302.0]|
+-------+
(array of sampled values, one per band)

rst_setcrs

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio + pyproj. Stamps the CRS without reprojecting.

Signature: rst_setcrs(tile: Column, crs: Column): Column — Stamp a CRS onto a raster that lacks (or has a wrong) spatial reference, from a CRS string (EPSG:x / ESRI:x / WKT / PROJ4; an int-castable string is treated as a SRID). Does NOT reproject — only rewrites the CRS metadata. Use rst_transformcrs when you need an actual reprojection. See Coordinate Reference Systems.

Distinct from rst_setsrid (integer EPSG only): rst_setcrs accepts any CRS string — an authority code (EPSG:3857, ESRI:54008), WKT, or PROJ4 — so a non-EPSG CRS can be applied. An int-castable string ('4326') behaves like rst_setsrid(tile, 4326). See the CRS: SRID int vs CRS string note above.

-- Relabel the tile's CRS to Web Mercator without warping pixels.
-- Accepts authority strings (EPSG:/ESRI:), WKT, or PROJ4; an int-castable
-- string ('4326') behaves like rst_setsrid(tile, 4326).
-- Use rst_transformcrs if you actually need a reprojection.
SELECT gbx_rst_setcrs(tile, 'EPSG:3857') AS tagged FROM rasters;
Example output
+-----------------------------------------------------------+
|tagged |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_setsrid

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by rasterio. Stamps the CRS without reprojecting.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_setsrid(tile: Column, srid: Column): Column — Stamp a SRID (>= 0; an EPSG or ESRI code) onto a raster that lacks (or has a wrong) spatial reference; 0 clears the CRS. Does NOT reproject — only rewrites the CRS metadata. A negative SRID is rejected, and a positive code that is neither EPSG nor ESRI raises when stamped. Use rst_transform when you need an actual reprojection, or rst_setcrs to stamp from a CRS string. See Coordinate Reference Systems.

-- Tag the tile as EPSG:4326 without warping pixels.
-- Use rst_transform if you actually need a reprojection.
SELECT gbx_rst_setsrid(tile, 4326) AS tagged FROM rasters;
Example output
+-----------------------------------------------------------+
|tagged |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_threshold

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by NumPy. This tier keeps each passing pixel's original value and sets failing pixels to NoData; the heavyweight tier instead returns a 0/1 binary mask (Float32). Choose the tier that matches the output you need.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_threshold(tile: Column, op: Column, value: Column): Column — Binarize the raster: pixels matching op value get 1, others get 0. op is one of >, >=, <, <=, ==, !=. Output is a Byte raster (0/1) sized to the input extent. Implemented as a gbx_rst_mapalgebra template.

-- Mark all pixels above 100 m as 1, others as 0.
SELECT gbx_rst_threshold(tile, '>', 100.0) AS mask FROM rasters;
Example output
+-----------------------------------------------------------+
|mask |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

Analysis

Higher-level analytical transforms wrapping single GDAL primitives — COG layout publishing, proximity surfaces, contour extraction, and viewshed analysis. See the Helios notebooks for a worked example of gbx_rst_cog_convert converting 3DEP DEMs to COGs and cataloging them in a STAC Delta table (NB03).

rst_cog_convert

LightweightHeavyweight
Lightweight tier (pyrx)

Re-encodes the tile as a Cloud Optimized GeoTIFF (validated with cog_validate). compression defaults to "auto" — a size-adaptive ZSTD level with a dtype-matched predictor (the GeoBrix materialize baseline; see Materialized Compression) — or an explicit codec name (zstd, deflate, lzw, lerc, jpeg, webp, none). The tile's metadata.driver is GTiff (a COG is a valid GeoTIFF).

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_cog_convert(tile: Column, [compression: Column, blocksize: Column = lit(512), overviewResampling: Column = lit("AVERAGE")]): Column — Re-layout a raster tile as a Cloud Optimized GeoTIFF via gdal.Translate -of COG. Both tiers use a ZSTD + dtype-predictor baseline. compression accepts an explicit codec on either tier — ZSTD, DEFLATE, LZW, NONE, LERC, JPEG, WEBP — and its default is ZSTD on the heavyweight tier. The lightweight tier additionally accepts AUTO (its default): a size-adaptive ZSTD level with the dtype predictor. blocksize is the internal tile size in pixels (square). overviewResampling is the algorithm for the auto-generated overview pyramid. Output is a GTiff-on-disk variant suitable for HTTP range serving. See Materialized Compression for the codec/level details and when to override. See Materialized Compression for the codec/level details and when to override.

-- Convert to COG with ZSTD compression, 512-pixel blocks, AVERAGE overviews.
-- The lightweight tier also accepts 'AUTO' (size-adaptive ZSTD + dtype
-- predictor, the default); pass 'DEFLATE' for a portable hand-off file.
-- See the Materialized Compression page.
SELECT gbx_rst_cog_convert(tile, 'ZSTD', 512, 'AVERAGE') AS cog
FROM rasters;
Example output
+-----------------------------------------------------------+
|cog |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+

rst_contour

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by scikit-image (measure.find_contours). Returns ARRAY<struct(geom_wkb, value)> of contour LineStrings (in the raster CRS) at each fixed level, or at base + k*interval across the data range when levels is empty; NoData is masked before tracing. The marching-squares line geometry differs slightly from the heavyweight GDAL contours.

Signature: rst_contour(tile: Column, levels: Column, [interval: Column = lit(0.0), base: Column = lit(0.0), attrField: Column = lit("elev")]): Column — Generate contour LineString features via gdal.ContourGenerateEx. Pass a non-empty levels ARRAY<DOUBLE> for fixed contour values, or pass array() and set interval (>0) for equal-step contours at base + n*interval. Returns ARRAY<struct(geom_wkb BINARY, value DOUBLE)> — one entry per contour line in the source raster's CRS.

-- Equal-interval contours every 50 m. Pass array() of fixed levels to override.
SELECT gbx_rst_contour(tile, array(), 50.0, 0.0, 'elev') AS contours
FROM dem_rasters;
Example output
+-----------------------------------------------------------------------------------------------------------------+
|contours |
+-----------------------------------------------------------------------------------------------------------------+
|[{[BINARY], 50.0}, {[BINARY], 100.0}, {[BINARY], 150.0}, {[BINARY], 200.0}, {[BINARY], 250.0}, {[BINARY], 300.0}]|
+-----------------------------------------------------------------------------------------------------------------+
(array of contour features: LineString geometry + elevation)

rst_proximity

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by SciPy (scipy.ndimage.distance_transform_edt). Distance to the nearest source pixel (target_values, or any non-zero pixel by default), in GEO (CRS units) or PIXEL units; pixels beyond max_distance → NoData −1.0. Single-band Float32.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_proximity(tile: Column, [targetValues: Column = null, distUnits: Column = lit("GEO"), maxDistance: Column = null]): Column — Compute a Float32 raster where each pixel holds the distance to the nearest source pixel via gdal.ComputeProximity. targetValues is a comma-separated list of source-pixel values (e.g. "1,2,3"); null means any non-NoData pixel is a target. distUnits is "GEO" (CRS ground units, default) or "PIXEL". maxDistance caps the output; pixels beyond it get the NoData sentinel -1.0.

-- Distance in pixels to any non-NoData pixel; cap distances at 100 pixels.
SELECT gbx_rst_proximity(tile, '', 'PIXEL', cast(100.0 as double)) AS dist
FROM rasters;
Example output
+-----------------------------------------------------------+
|dist |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(distance in pixels to nearest non-NoData pixel, capped at 100)

rst_viewshed

LightweightHeavyweight
Lightweight tier (pyrx)

Powered by xarray-spatial (xrspatial.viewshed). Returns a Byte tile (255 visible / 0 invisible) from a DEM tile and a POINT observer. The CPU line-of-sight scan differs from the heavyweight GDAL sweep (no earth-curvature correction), but the binary visible/invisible classification matches. Pulls numba — the heaviest pyrx dependency.

Lightweight Python — virtual-tile force-output

The lightweight Python binding accepts three optional keyword arguments the SQL and heavyweight tiers do not — virtualize_dir, virtualize_prefix, and materialize — controlling whether the produced tile carries raster bytes or a bytes-free virtual reference. See Virtual-tile force-output params.

Signature: rst_viewshed(tile: Column, observerGeom: Column, observerHeight: Column, [targetHeight: Column = lit(1.6), maxDistance: Column = null]): Column — Compute a binary viewshed Byte raster (255 = visible, 0 = invisible / out-of-range) from a DEM tile and an observer POINT via gdal.ViewshedGenerate. observerGeom is WKB / WKT POINT; it is reprojected from its source CRS to the raster CRS (an EWKB/EWKT embedded SRID wins, else the optional crs argument, else assumed already aligned). Non-POINT geometries raise an error at execution time. Heights are above the DEM at each pixel. maxDistance clips the search radius; null = unlimited. See Coordinate Reference Systems.

-- Visibility from observer at (-73.5 40.5), eye 100 m, target 1.6 m, cap 5000 m.
SELECT gbx_rst_viewshed(tile, 'POINT(-73.5 40.5)', 100.0, 1.6, 5000.0) AS vs
FROM dem_rasters;
Example output
+-----------------------------------------------------------+
|vs |
+-----------------------------------------------------------+
|{0, <raster bytes>, <virtual path>, {driver -> GTiff, ...}}|
+-----------------------------------------------------------+
(binary viewshed: 1=visible, 0=not visible)

Heavyweight-tier specifics

Every RasterX function runs in both execution tiers, so the per-function reference above applies regardless of tier. This section documents one heavyweight-tier execution detail: the GDAL VRT Python pixel-function configuration used by gbx_rst_combineavg / gbx_rst_derivedband (and their _agg forms).

VRT Python pixel functions

gbx_rst_combineavg, gbx_rst_combineavg_agg, gbx_rst_derivedband, and gbx_rst_derivedband_agg evaluate a Python expression on each pixel via GDAL's VRT Python pixel-function API. That API is gated behind the GDAL config option GDAL_VRT_ENABLE_PYTHON, which GeoBrix sets to NO at executor startup (see Security - Restrict GDAL drivers). When you call one of the four functions above, GeoBrix flips the option to YES for the duration of that call only — via the internal GDALManager.withVrtPython bracket — and restores NO immediately on return. You don't need to set anything on the cluster or in your notebook to use the built-in functions.

When you need to enable it yourself

If you're invoking the GDAL Python bindings (from osgeo import gdal) directly — outside the built-in RasterX functions — and you read a VRT that declares a <PixelFunctionLanguage>Python</...> band, you'll get an empty/null read unless you enable the option in the same process. Pick one of:

Python — programmatic, scoped to your read. Recommended in all cases. Mirrors what GeoBrix does internally, works for both driver-side pyspark.sql calls and inside mapPartitions / mapInPandas UDFs that load VRT-with-pyfunc via osgeo.gdal, and survives interleaving with GeoBrix built-in calls (each GeoBrix call resets the option to NO on exit, so re-set it on every read):

from osgeo import gdal

gdal.SetConfigOption("GDAL_VRT_ENABLE_PYTHON", "YES")
try:
ds = gdal.Open("/path/to/your/vrt-with-pixel-function.vrt")
arr = ds.GetRasterBand(1).ReadAsArray()
ds = None
finally:
gdal.SetConfigOption("GDAL_VRT_ENABLE_PYTHON", "NO")

Cluster env var — for Python-worker processes only. Setting spark.executorEnv.GDAL_VRT_ENABLE_PYTHON YES on the cluster works for Python UDF workers (a separate process from the JVM, where GDAL initializes from env vars). It does not help JVM-side reads — GeoBrix calls gdal.SetConfigOption("GDAL_VRT_ENABLE_PYTHON", "NO") at executor JVM startup, and SetConfigOption takes precedence over the env var. Prefer the programmatic form above unless you have a strong reason to globally enable.

Scala / JVM code. If you're writing custom Spark expressions that consume Python-pixel VRTs, wrap the read/translate in the same helper GeoBrix uses internally — it refcounts the option so concurrent tasks on the same executor JVM compose safely:

import com.databricks.labs.gbx.rasterx.gdal.GDALManager

val result = GDALManager.withVrtPython {
val ds = org.gdal.gdal.gdal.Open(vrtPath)
// ... GDAL reads / translates here see the Python pixel function ...
ds
}

Trusted-modules variant

GDAL also accepts GDAL_VRT_ENABLE_PYTHON=TRUSTED_MODULES plus a GDAL_VRT_PYTHON_TRUSTED_MODULES allowlist if you want pixel-function code restricted to specific Python module prefixes. GeoBrix uses the plain YES form because the pixel-function source is constructed in-process from trusted (geobrix-generated) strings, never from user-supplied VRT XML on disk. If your custom code path reads VRTs whose <PixelFunctionCode> originates from less-trusted sources, switch to the TRUSTED_MODULES form and allowlist only what you intend to load.


Escape hatches

When a raster operation isn't in the rst_* surface, drop down to rasterio/NumPy per tile (lightweight tier). These are Python-only helpers on databricks.labs.gbx.pyrx.functions — not SQL functions, and not registered as gbx_rst_*.

tile_to_numpy

from databricks.labs.gbx.pyrx.functions import tile_to_numpy

arr = tile_to_numpy(tile_or_bytes) # -> np.ndarray, shape (bands, rows, cols)

Read a tile's raster into a NumPy array (all bands). Accepts either a tile struct (a Row/dict with a raster field) or raw bytes. Useful when you've collected a tile to the driver, or inside your own UDF.

rst_apply

from pyspark.sql.types import DoubleType
from databricks.labs.gbx.pyrx.functions import rst_apply

df.select(
rst_apply("tile", lambda ds: float(ds.read(1).mean()), returnType=DoubleType()).alias("band1_mean")
)

Apply your own function to each tile's open rasterio dataset, returning one scalar per row. fn receives a rasterio DatasetReader; the return value must match returnType (default DoubleType(); any Spark DataType). A null/empty tile yields null. This is the "GeoBrix doesn't have function X — run my own rasterio per tile" path; it returns a scalar (raster→raster transforms are the domain of rst_mapalgebra / rst_derivedband).

For rendering tiles and building maps from results, see the Visualization (gbx.vizx) page.


Next Steps