Function Reference
GridX is fully lightweight as of v0.4.0: the quadbin (gbx_quadbin_*), BNG (gbx_bng_*), and custom-grid (gbx_custom_*) functions all run in both tiers LightweightHeavyweight. Each section below is marked with its tier. See Choosing an Execution Tier for the lightweight vs heavyweight comparison.
Complete reference for all GridX discrete-global-grid functions — CARTO Quadbin v0 and British National Grid (BNG).
Overview
GridX is GeoBrix's discrete-global-grid indexing package. It ships CARTO quadbin v0 for web-mercator-aligned global indexing, British National Grid (BNG) for Great Britain workloads, and custom user-defined grids — and pairs with the product's native H3 for global hex indexing.
- Quadbin (CARTO v0) — a global zoom-indexed tile addressing scheme aligned with web-mercator slippy maps, compatible with CARTO's CDB_QuadKey IDs. Cell
(z, x, y)coordinates align with the same XYZ tile grid that PMTiles / MVT readers consume — natural for slippy-map heatmaps and global analytics. - BNG (British National Grid) — the Ordnance Survey National Grid (OSGB36) used in Great Britain for spatial indexing and location-based services. Specialized for UK-based spatial data.
- Custom user-defined grids — define a regional or equal-area grid and get cell math, polyfill, and tessellation on it.
- Quadbin:
databricks.labs.gbx.gridx.quadbin(Python) /com.databricks.labs.gbx.gridx.quadbin(Scala) - BNG:
databricks.labs.gbx.gridx.bng(Python) /com.databricks.labs.gbx.gridx.bng(Scala)
Use RegisterBatch with functions=gridx.quadbin or functions=gridx.bng to register just one subpackage, or functions=all for everything.
Key Features
- Grid Cell Operations: Create, manipulate, and query BNG grid cells
- Area Calculations: Calculate areas of grid cells at different precisions (returns square kilometres)
- Coordinate Conversion: Convert between grid references and coordinates
- Spatial Indexing: Use BNG or quadbin for efficient spatial indexing
- Multi-Resolution Support: Work with different grid resolutions (BNG: 1–6 integer indices; Quadbin: zoom 0..26)
- K-Ring / K-Loop Neighbourhoods: Filled rings and hollow rings for both grid systems
- Polyfill and Tessellation: Cover geometries with cells; tessellation returns per-cell clipped chip geometries
- Custom Grids: Define your own regional or equal-area grid systems (cell math, polyfill, tessellation)
Setup
With GeoBrix already installed, register GridX in your session before running any example.
- Lightweight (pygx)
- Heavyweight
from databricks.labs.gbx.pygx import functions as gx
gx.register(spark) # registers all gbx_bng_*, gbx_quadbin_*, gbx_custom_* SQL functions
# BNG
from databricks.labs.gbx.gridx.bng import functions as bx
bx.register(spark)
# Quadbin
from databricks.labs.gbx.gridx.quadbin import functions as qx
qx.register(spark)
# Custom grid
from databricks.labs.gbx.gridx.custom import functions as cx
cx.register(spark)
The examples on this page read from ten canonical DataFrames, one per fixture group. Each is available as a temp view for SQL examples. Point the placeholders at your own data to reproduce the examples:
| View / DataFrame | Schema | Backed by | Backs |
|---|---|---|---|
bng_cells | cellid STRING | Inline literal 'TQ3080' (1km cell, central London, EPSG:27700) | BNG scalar ops: bng_aswkb, bng_aswkt, bng_cellarea, bng_centroid, bng_kring, bng_kloop |
bng_cell_pairs | cellid1 STRING, cellid2 STRING | Inline literals 'TQ3080', 'TQ3081' (adjacent cells, distance = 1) | bng_distance, bng_euclideandistance |
bng_points | easting INT, northing INT, geom STRING | Easting 530000, northing 180000, WKT point (EPSG:27700) | bng_pointascell, bng_eastnorthasbng |
bng_polygons | geom STRING | 3km × 3km BNG polygon in EPSG:27700 (London area) | bng_geomkring, bng_geomkloop, bng_polyfill, bng_tessellate, and the 5 *explode generators |
bng_chips | chip STRUCT<cellid STRING, core BOOLEAN, chip BINARY> | 9 tessellation chips from the BNG polygon at resolution 3 | bng_cellintersection, bng_cellunion, bng_cellintersection_agg, bng_cellunion_agg |
quadbin_cells | cell LONG | Inline literal 5233961839712272383 (San Francisco, zoom 10) | quadbin_aswkb, quadbin_centroid, quadbin_resolution, quadbin_kring, quadbin_cellunion |
quadbin_cell_pairs | cell1 LONG, cell2 LONG | Two cells at (0.0, 0.0, z10) and (0.0, 0.1, z10) — distance = 1 | quadbin_distance |
quadbin_polygons | geom STRING | WGS84 polygon (-1,-1) → (1,1) | quadbin_polyfill, quadbin_tessellate |
quadbin_kring_cells | cell LONG | 9 cells from kring(SF-z10, k=1) | quadbin_cellunion_agg |
custom_grids | grid STRUCT, cell LONG, point STRING | BNG-like custom grid; cell at POINT(530000 180000), resolution 5 | All 7 custom_* functions |
All ten views are built from inline literals in the doc-test fixture helpers (no external files or /Volumes dependency, so the examples run anywhere).
plot_staticvizx.plot_static renders a column of cell ids straight from a Spark DataFrame as a static, GitHub-renderable map over a basemap — and it's the one helper that covers every GridX grid: pass grid_system="quadbin", "bng", or "custom" (as well as "h3"). Each grid's native CRS is handled for you (e.g. BNG's EPSG:27700 is reprojected for the basemap), and "custom" takes the same grid spec via grid_conf=. It's the quickest way to eyeball the cells the functions below produce. See plot_static for the full parameter list.
Examples — Conventions
How to read the four tabs
Every function on this page shows one example, expressed identically across four tabs:
| Tab | Tier | Badge |
|---|---|---|
| SQL | Both (default) | — |
| Python (light) | pygx lightweight tier | — |
| Python (heavy) | heavyweight tier | Blue |
| Scala | heavyweight tier | Blue |
All four tabs operate on the same input fixture with the same arguments. Where a genuine tier difference exists — a diverging output schema or a behavior available only in one tier — the affected tab carries a labeled :::note. A difference without a label is a documentation error.
In each Python example, df = spark.table("<view>") or an equivalent inline spark.sql(...) call loads the canonical fixture. Each SQL example reads FROM <view> or uses an inline literal — no separate CREATE TEMP VIEW step is shown.
Output representation
The output cells in every function table follow a uniform convention so readers can compare tabs at a glance.
Cell-id strings — BNG cell-ids (e.g. 'TQ3080') and quadbin cells (e.g. 5233961839712272383) are shown in full when short.
Binary geometry ([E]WKB) — geometry returned as BINARY is elided with one token and a format annotation. Use (WKB binary) when no SRID is embedded; (EWKB binary) when an SRID is embedded (quadbin functions embed SRID 4326):
... (WKB binary)
... (EWKB binary)
WKT strings — short WKT strings are shown in full; longer strings are truncated with a type annotation:
POLYGON ((530000 180000, ...))
POLYGON (... (WKT)
Cell-id arrays — arrays of cell-ids show the first few entries followed by ... when the array is long:
['TQ2979', 'TQ2980', 'TQ2981', ..., 'TQ3181'] (9 cells)
Doubles / numeric scalars — shown as the real value (e.g. 1.0 for bng_cellarea).
Cell width — output cells are capped at approximately 60 characters. A longer value is truncated with ... and annotated with its type.
Identical-across-tier values — when all four tabs produce the same result (e.g. 'TQ3080' from bng_pointascell), each tab shows that value identically with the same annotation. Genuine tier differences are called out in a labeled :::note.
BNG domain rules
The following rules apply to all BNG functions (gbx_bng_*):
- Coordinate system — BNG geometry inputs (points and polygons) must be in EPSG:27700 eastings/northings. WGS84 lon/lat coordinates (e.g.
POINT(-0.1278 51.5074)) yield empty arrays or null results — this is the most common source of confusion. - Resolution — accepts integer indices ±1..±6 (1 = 100km, 2 = 10km, 3 = 1km, 4 = 100m, 5 = 10m, 6 = 1m; negative values are quadrants) or string keys from the resolution map (e.g.
'1km','100m','10m'). Never pass metres-as-integer (e.g.1000) — that interpretation is not supported byBNG.getResolutionand raises an error. bng_cellareareturns square kilometres — not square metres. A 1km cell returns1.0.- Cell-id format — standard BNG grid references (e.g.
'TQ3080'). At resolution 3 (1km), the format is two letters + four digits; the resolution level is encoded in the string length.
BNG *explode generators — SQL LATERAL only
The five BNG explode generators (bng_kringexplode, bng_kloopexplode, bng_geomkringexplode, bng_geomkloopexplode, bng_tessellateexplode) are Python UDTFs in the lightweight tier — they have no Python DataFrame Column form. Calling them as Column expressions raises NotImplementedError. Use SQL LATERAL for both tiers:
SELECT t.*
FROM (SELECT 'TQ3080' AS cellid, 1 AS k) src,
LATERAL gbx_bng_kringexplode(src.cellid, src.k) t
The Python (light) tab for these functions shows the same spark.sql("... LATERAL ...") invocation.
Quadbin (CARTO v0)
LightweightHeavyweight Quadbin runs in both tiers. The lightweight tier is the pygx quadbin package — powered by the quadbin library + shapely; quadbin_distance / quadbin_polyfill cell math mirrors the heavyweight Quadbin.scala, and geometry outputs are EWKB SRID 4326 — identical gbx_quadbin_* SQL names, so it is a drop-in swap.
GeoBrix v0.4.0 adds a gridx/quadbin subpackage implementing the CARTO quadbin v0 64-bit packed (z, x, y) tile encoding used by Snowflake, dbt, Felt, and CARTO. Coordinates are EPSG:4326 lon/lat on the user-facing API; cells are encoded as web-mercator XYZ tiles internally. Resolutions range from 0 (whole world) to 26 (sub-metre).
Quadbin functions are under gridx.quadbin — independent of gridx.bng. Call functions.register(spark) once per session to install the gbx_quadbin_* SQL functions.
CARTO Quadbin v0 cells encode (z, x, y) web-mercator tile coordinates as a single BIGINT. Cell IDs are interoperable with CARTO's CDB_QuadKey and align with the slippy-map tile grid used by gbx_rst_xyzpyramid and gbx_st_asmvt_pyramid. Exact cell-set parity between the lightweight and heavyweight tiers is enforced by the cross-tier parity suite.
Resolution (zoom) range:
gbx_quadbin_pointascell,gbx_quadbin_resolution,gbx_quadbin_kring,gbx_quadbin_distanceaccept zoom0..26.gbx_quadbin_polyfillandgbx_quadbin_tessellateaccept zoom0..20.
quadbin_pointascell
LightweightHeavyweightConvert a lon/lat coordinate (EPSG:4326) to the quadbin cell containing it at the given zoom.
Powered by the quadbin package (numpy-vectorized encoder). Encodes WGS84 lon/lat to a quadbin cell at the given zoom; bit-identical to the heavyweight Quadbin.scala (incl. the antimeridian/pole tile clamp).
Signature: quadbin_pointascell(longitude: Column, latitude: Column, zoom: Column): Column
Returns:
BIGINTquadbin cell ID
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_pointascell(-122.4194, 37.7749, 10) as sf_cell;
+-------------------+
|sf_cell |
+-------------------+
|5233961839712272383|
+-------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.sql("SELECT -122.4194 AS lon, 37.7749 AS lat, 10 AS zoom")
result = df.select(
gx.quadbin_pointascell(f.col("lon"), f.col("lat"), f.col("zoom")).alias(
"sf_cell"
)
).first()
+-------------------+
|sf_cell |
+-------------------+
|5233961839712272383|
+-------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.sql("SELECT -122.4194 AS lon, 37.7749 AS lat, 10 AS zoom")
result = df.select(
qx.quadbin_pointascell(f.col("lon"), f.col("lat"), f.col("zoom")).alias(
"sf_cell"
)
).first()
+-------------------+
|sf_cell |
+-------------------+
|5233961839712272383|
+-------------------+
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// San Francisco at zoom 10 (WGS84 lon/lat input; quadbin resolution 0..26)
val df = spark.sql("SELECT -122.4194 AS lon, 37.7749 AS lat, 10 AS zoom")
val result = df.select(
qx.quadbin_pointascell(col("lon"), col("lat"), col("zoom")).alias("sf_cell")
)
result.show()
+-------------------+
|sf_cell |
+-------------------+
|5233961839712272383|
+-------------------+
quadbin_aswkb
LightweightHeavyweightReturn the quadbin cell footprint as EWKB (SRID=4326) — the four-corner polygon of the tile in lon/lat.
Powered by the quadbin package + shapely. Cell boundary polygon as EWKB (SRID 4326).
Signature: quadbin_aswkb(cellId: Column): Column
Returns:
- Binary EWKB polygon (SRID-tagged 4326)
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_aswkb(gbx_quadbin_pointascell(-122.4194, 37.7749, 10)) AS wkb;
+--------+
|wkb |
+--------+
|[binary]|
+--------+
... (EWKB binary — quadbin cell footprint polygon, SRID 4326)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_cells")
result = df.select(gx.quadbin_aswkb(f.col("cell")).alias("wkb")).first()
+--------+
|wkb |
+--------+
|[binary]|
+--------+
... (EWKB binary — quadbin cell footprint polygon, SRID 4326)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_cells")
result = df.select(qx.quadbin_aswkb(f.col("cell")).alias("wkb")).first()
+--------+
|wkb |
+--------+
|[binary]|
+--------+
... (EWKB binary — quadbin cell footprint polygon, SRID 4326)
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_cells view (cell = 5233961839712272383, SF at z10)
// Returns the four-corner boundary polygon as EWKB (SRID 4326)
val df = spark.table("quadbin_cells")
val result = df.select(qx.quadbin_aswkb(col("cell")).alias("wkb"))
result.show()
+--------+
|wkb |
+--------+
|[binary]|
+--------+
... (EWKB binary — quadbin cell footprint polygon, SRID 4326)
quadbin_centroid
LightweightHeavyweightReturn the quadbin cell centroid as an EWKB POINT (SRID=4326).
Powered by the quadbin package + shapely. Cell centroid (bbox-corner mean, matching Quadbin.scala) as EWKB point (SRID 4326).
Signature: quadbin_centroid(cellId: Column): Column
Returns:
- Binary EWKB point (SRID-tagged 4326)
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_centroid(gbx_quadbin_pointascell(-122.4194, 37.7749, 10)) AS centroid;
+--------+
|centroid|
+--------+
|[binary]|
+--------+
... (EWKB binary — POINT at SF z10 cell centroid, SRID 4326)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_cells")
result = df.select(gx.quadbin_centroid(f.col("cell")).alias("centroid")).first()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (EWKB binary — POINT at SF z10 cell centroid, SRID 4326)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_cells")
result = df.select(qx.quadbin_centroid(f.col("cell")).alias("centroid")).first()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (EWKB binary — POINT at SF z10 cell centroid, SRID 4326)
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_cells view (cell = 5233961839712272383, SF at z10)
// Returns the bbox-corner mean as EWKB POINT (SRID 4326)
val df = spark.table("quadbin_cells")
val result = df.select(qx.quadbin_centroid(col("cell")).alias("centroid"))
result.show()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (EWKB binary — POINT at SF z10 cell centroid, SRID 4326)
quadbin_resolution
LightweightHeavyweightReturn the resolution (zoom) of a quadbin cell.
Powered by the quadbin package (numpy-vectorized). Extracts the zoom level from a cell id.
Signature: quadbin_resolution(cellId: Column): Column
Returns:
INTzoom level (0..26)
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_resolution(gbx_quadbin_pointascell(-122.4194, 37.7749, 10)) AS z;
+--+
|z |
+--+
|10|
+--+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_cells")
result = df.select(gx.quadbin_resolution(f.col("cell")).alias("z")).first()
+--+
|z |
+--+
|10|
+--+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_cells")
result = df.select(qx.quadbin_resolution(f.col("cell")).alias("z")).first()
+--+
|z |
+--+
|10|
+--+
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_cells view (cell = 5233961839712272383, SF at z10)
// Extracts the zoom level → returns INT 10
val df = spark.table("quadbin_cells")
val result = df.select(qx.quadbin_resolution(col("cell")).alias("z"))
result.show()
+--+
|z |
+--+
|10|
+--+
quadbin_polyfill
LightweightHeavyweightPolyfill a geometry's bounding box with all quadbin cells at the given zoom.
Powered by the quadbin package + shapely. Enumerates the cells covering the geometry's bounding box at the resolution, mirroring Quadbin.scala's envelope semantics.
Signature: quadbin_polyfill(geom: Column, zoom: Column): Column
Returns:
ARRAY<BIGINT>of cell IDs covering the bbox
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_polyfill('POLYGON((-1 -1, 1 -1, 1 1, -1 1, -1 -1))', 5) AS cells;
+--------------------------+
|cells |
+--------------------------+
|[5211790668774506495, ...]|
+--------------------------+
... (4 cells covering the WGS84 polygon at zoom 5)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_polygons")
result = df.select(
gx.quadbin_polyfill(f.col("geom"), f.lit(5)).alias("cells")
).first()
+--------------------------+
|cells |
+--------------------------+
|[5211790668774506495, ...]|
+--------------------------+
... (4 cells covering the WGS84 polygon at zoom 5)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_polygons")
result = df.select(
qx.quadbin_polyfill(f.col("geom"), f.lit(5)).alias("cells")
).first()
+--------------------------+
|cells |
+--------------------------+
|[5211790668774506495, ...]|
+--------------------------+
... (4 cells covering the WGS84 polygon at zoom 5)
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_polygons view (WGS84 polygon near origin, z=5 → 4 cells)
val df = spark.table("quadbin_polygons")
val result = df.select(qx.quadbin_polyfill(col("geom"), lit(5)).alias("cells"))
result.show(truncate = false)
+--------------------------+
|cells |
+--------------------------+
|[5211790668774506495, ...]|
+--------------------------+
... (4 cells covering the WGS84 polygon at zoom 5)
quadbin_kring
LightweightHeavyweightReturn all cells within Chebyshev distance k of a quadbin cell (inclusive of the center cell).
Powered by the quadbin package. All cells within Chebyshev distance k (inclusive).
Signature: quadbin_kring(cellId: Column, k: Column): Column
Returns:
ARRAY<BIGINT>of cell IDs (length(2k+1)^2)
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_kring(gbx_quadbin_pointascell(-122.4194, 37.7749, 10), 1) AS kring;
+-------------------------------------+
|kring |
+-------------------------------------+
|[5233961839712272383, ..., (9 cells)]|
+-------------------------------------+
... (9 cells: SF z10 center plus 8 surrounding cells at k=1)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_cells")
result = df.select(gx.quadbin_kring(f.col("cell"), f.lit(1)).alias("kring")).first()
+-------------------------------------+
|kring |
+-------------------------------------+
|[5233961839712272383, ..., (9 cells)]|
+-------------------------------------+
... (9 cells: SF z10 center plus 8 surrounding cells at k=1)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_cells")
result = df.select(qx.quadbin_kring(f.col("cell"), f.lit(1)).alias("kring")).first()
+-------------------------------------+
|kring |
+-------------------------------------+
|[5233961839712272383, ..., (9 cells)]|
+-------------------------------------+
... (9 cells: SF z10 center plus 8 surrounding cells at k=1)
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_cells view (cell = 5233961839712272383, SF at zoom 10)
// Returns ARRAY<BIGINT> — center plus 8 surrounding cells at k=1 → 9 cells
val df = spark.table("quadbin_cells")
val result = df.select(qx.quadbin_kring(col("cell"), lit(1)).alias("kring"))
result.show(truncate = false)
+-------------------------------------+
|kring |
+-------------------------------------+
|[5233961839712272383, ..., (9 cells)]|
+-------------------------------------+
... (9 cells: SF z10 center plus 8 surrounding cells at k=1)
quadbin_tessellate
LightweightHeavyweightTessellate a geometry into quadbin cells. Like quadbin_polyfill but returns the per-cell geometry chip alongside the cell ID, suitable for chip-based join patterns.
Powered by the quadbin package + shapely. Bbox polyfill then per-cell intersection with the input geometry; one STRUCT<cell, geom> per chip (EWKB, SRID 4326).
Signature: quadbin_tessellate(geom: Column, zoom: Column): Column
Returns:
ARRAY<STRUCT<cell: BIGINT, geom: BINARY>>
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_tessellate('POLYGON((-1 -1, 1 -1, 1 1, -1 1, -1 -1))', 5) AS chips;
+----------------------------------------------+
|chips |
+----------------------------------------------+
|[{5211790668774506495, [binary]}, {5212..., ..|
+----------------------------------------------+
... (4 chips: each quadbin cell paired with its clipped geometry WKB (SRID 4326))
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_polygons")
result = df.select(
gx.quadbin_tessellate(f.col("geom"), f.lit(5)).alias("chips")
).first()
+----------------------------------------------+
|chips |
+----------------------------------------------+
|[{5211790668774506495, [binary]}, {5212..., ..|
+----------------------------------------------+
... (4 chips: each quadbin cell paired with its clipped geometry WKB (SRID 4326))
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_polygons")
result = df.select(
qx.quadbin_tessellate(f.col("geom"), f.lit(5)).alias("chips")
).first()
+----------------------------------------------+
|chips |
+----------------------------------------------+
|[{5211790668774506495, [binary]}, {5212..., ..|
+----------------------------------------------+
... (4 chips: each quadbin cell paired with its clipped geometry WKB (SRID 4326))
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_polygons view (WGS84 polygon near origin, z=5 → 4 chips)
// Each chip: STRUCT<cell BIGINT, geom BINARY> (EWKB, SRID 4326)
val df = spark.table("quadbin_polygons")
val result = df.select(qx.quadbin_tessellate(col("geom"), lit(5)).alias("chips"))
result.show(truncate = false)
+----------------------------------------------+
|chips |
+----------------------------------------------+
|[{5211790668774506495, [binary]}, {5212..., ..|
+----------------------------------------------+
... (4 chips: each quadbin cell paired with its clipped geometry WKB (SRID 4326))
quadbin_cellunion
LightweightHeavyweightUnion an ARRAY<BIGINT> of quadbin cells into a single MultiPolygon EWKB.
Powered by shapely (union_all of the cell polygons). Dissolves an ARRAY<LONG> of cells into one EWKB MultiPolygon (SRID 4326).
Signature: quadbin_cellunion(cellIds: Column): Column
Returns:
- Binary EWKB multipolygon (SRID-tagged 4326)
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_cellunion(
gbx_quadbin_kring(gbx_quadbin_pointascell(-122.4194, 37.7749, 10), 1)
) AS union_geom;
+----------+
|union_geom|
+----------+
|[binary] |
+----------+
... (EWKB binary — MultiPolygon dissolving the SF z10 kring, SRID 4326)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_cells")
result = df.select(
gx.quadbin_cellunion(gx.quadbin_kring(f.col("cell"), f.lit(1))).alias(
"union_geom"
)
).first()
+-----------+
|union_geom |
+-----------+
|[binary] |
+-----------+
... (EWKB binary — MultiPolygon dissolving the SF z10 kring, SRID 4326)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_cells")
result = df.select(
qx.quadbin_cellunion(qx.quadbin_kring(f.col("cell"), f.lit(1))).alias(
"union_geom"
)
).first()
+-----------+
|union_geom |
+-----------+
|[binary] |
+-----------+
... (EWKB binary — MultiPolygon dissolving the SF z10 kring, SRID 4326)
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_cells view (cell = 5233961839712272383, SF at z10)
// Dissolves the k=1 kring (9 cells) into one EWKB MultiPolygon (SRID 4326)
val df = spark.table("quadbin_cells")
val result = df.select(
qx.quadbin_cellunion(
qx.quadbin_kring(col("cell"), lit(1))
).alias("union_geom")
)
result.show()
+-----------+
|union_geom |
+-----------+
|[binary] |
+-----------+
... (EWKB binary — MultiPolygon dissolving the SF z10 kring, SRID 4326)
quadbin_cellunion_agg
LightweightHeavyweight Grouped-agg UDFAggregate-level union: dissolve a column of quadbin cell IDs (grouped per partition) into a single MultiPolygon EWKB. Use this instead of gbx_quadbin_cellunion when your cell IDs are spread across rows rather than already collected into an array.
Powered by shapely. Grouped aggregate — groupBy(...).agg(gx.quadbin_cellunion_agg("cell")) dissolves a group's cell ids into one EWKB MultiPolygon (SRID 4326).
Signature: quadbin_cellunion_agg(cell: Column): Column
Returns:
BINARYEWKB multipolygon (SRID-tagged 4326) representing the dissolved coverage
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT region, gbx_quadbin_cellunion_agg(cell) AS coverage
FROM (
SELECT 'R1' AS region,
explode(gbx_quadbin_kring(gbx_quadbin_pointascell(-122.4194, 37.7749, 10), 1)) AS cell
) t
GROUP BY region;
+------+--------+
|region|coverage|
+------+--------+
|R1 |[binary]|
+------+--------+
... (BINARY EWKB — dissolved coverage of all 9 kring cells around SF z10, SRID 4326)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_kring_cells")
df_keyed = df.withColumn("region", f.lit("R1"))
result = (
df_keyed.groupBy("region")
.agg(gx.quadbin_cellunion_agg("cell").alias("coverage"))
.first()
)
+------+--------+
|region|coverage|
+------+--------+
|R1 |[binary]|
+------+--------+
... (BINARY EWKB — dissolved coverage of all 9 kring cells around SF z10, SRID 4326)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_kring_cells")
df_keyed = df.withColumn("region", f.lit("R1"))
result = (
df_keyed.groupBy("region")
.agg(qx.quadbin_cellunion_agg(f.col("cell")).alias("coverage"))
.first()
)
+------+--------+
|region|coverage|
+------+--------+
|R1 |[binary]|
+------+--------+
... (BINARY EWKB — dissolved coverage of all 9 kring cells around SF z10, SRID 4326)
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_kring_cells view (9 cells from kring of SF z10, k=1)
// Groups all cells under 'R1' and dissolves them into one EWKB MultiPolygon.
// Returns BINARY (SRID 4326) — both tiers agree (no struct divergence).
val df = spark.table("quadbin_kring_cells").withColumn("region", lit("R1"))
val result = df.groupBy("region")
.agg(qx.quadbin_cellunion_agg(col("cell")).alias("coverage"))
result.show(truncate = false)
+------+--------+
|region|coverage|
+------+--------+
|R1 |[binary]|
+------+--------+
... (BINARY EWKB — dissolved coverage of all 9 kring cells around SF z10, SRID 4326)
quadbin_distance
LightweightHeavyweightChebyshev (king-move) distance between two quadbin cells at the same resolution.
Powered by the quadbin package. Chebyshev distance on tile coordinates; mirrors Quadbin.scala (errors if the two cells differ in resolution).
Signature: quadbin_distance(cellA: Column, cellB: Column): Column
Returns:
INTcell-step distance
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_quadbin_distance(
gbx_quadbin_pointascell(0.0, 0.0, 10),
gbx_quadbin_pointascell(0.0, 0.1, 10)
) AS d;
+-+
|d|
+-+
|1|
+-+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = spark.table("quadbin_cell_pairs")
result = df.select(
gx.quadbin_distance(f.col("cell1"), f.col("cell2")).alias("d")
).first()
+--+
|d |
+--+
|1 |
+--+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.quadbin import functions as qx
df = spark.table("quadbin_cell_pairs")
result = df.select(
qx.quadbin_distance(f.col("cell1"), f.col("cell2")).alias("d")
).first()
+--+
|d |
+--+
|1 |
+--+
import com.databricks.labs.gbx.gridx.quadbin.{functions => qx}
import org.apache.spark.sql.functions._
// Reads the quadbin_cell_pairs view (cell1 and cell2 at zoom 10, distance=1)
val df = spark.table("quadbin_cell_pairs")
val result = df.select(
qx.quadbin_distance(col("cell1"), col("cell2")).alias("d")
)
result.show()
+--+
|d |
+--+
|1 |
+--+
British National Grid (BNG)
LightweightHeavyweight BNG runs in both tiers. The lightweight tier is the pygx BNG package — powered by a pure-Python port of BNG.scala + shapely for geometry; identical gbx_bng_* SQL names, so it is a drop-in swap. Cell IDs are STRING references; geometry outputs are plain WKB in EPSG:27700 coordinates with no SRID (unlike quadbin's EWKB SRID 4326). Cell-id math (bng_eastnorthasbng, bng_pointascell, bng_distance, bng_kring, bng_polyfill, …) is exact-parity with the heavyweight tier; exact cell-set parity is enforced by the cross-tier parity suite.
The British National Grid is the national coordinate system for Great Britain, based on the Ordnance Survey National Grid (OSGB36). It divides Great Britain into grid squares identified by letter-based prefixes and numeric coordinates.
BNG Structure
- Grid Squares: 100km x 100km squares identified by two letters (e.g., "TQ" for London, "NT" for Edinburgh)
- Eastings and Northings: Numeric coordinates within each grid square (EPSG:27700)
- Resolution Indices: Integer indices 1..6 (1=100km, 2=10km, 3=1km, 4=100m, 5=10m, 6=1m); negative indices select quadrant sub-cells. String keys (e.g.
"1km","100m") are also accepted viaBNG.resolutionMap.
BNG Grid Reference Format
BNG references follow the format: [Letters][Eastings][Northings]
Examples:
TQ 38 80— 1km precision (Tower of London area)TQ 3800 8000— 100m precisionTQ 38000 80000— 10m precisionSU 12 34— Different grid square
Precision Levels
| Precision | Grid Size | Example | Use Case |
|---|---|---|---|
| 100000m | 100km x 100km | TQ | Regional analysis |
| 10000m | 10km x 10km | TQ38 | District-level |
| 1000m | 1km x 1km | TQ3080 | Local area analysis |
| 100m | 100m x 100m | TQ308808 | Neighborhood level |
| 10m | 10m x 10m | TQ30808080 | Building level |
| 1m | 1m x 1m | TQ3080080800 | Precise location |
Major Grid Squares
Major 100km grid squares in Great Britain:
- TQ — London area
- SU — South Hampshire
- NT — Edinburgh area
- SD — Lake District
- ST — Bristol area
Conversion Functions
Functions to convert BNG cell IDs to standard geometry formats.
bng_aswkb
LightweightHeavyweightConvert a BNG cell ID to Well-Known Binary (WKB) format.
Powered by a pure-Python port of BNG.scala + shapely. The cell footprint polygon as plain WKB in EPSG:27700 (no SRID).
Signature: bng_aswkb(cellId: Column): Column
Parameters:
cellId- BNG cell reference string
Returns:
- Binary WKB geometry representation
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_aswkb('TQ3080') as wkb_geom;
+--------+
|wkb_geom|
+--------+
|[binary]|
+--------+
... (WKB binary)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_cells_df(spark)
result = df.select(gx.bng_aswkb(f.col("cellid")).alias("wkb")).first()
+--------+
|wkb |
+--------+
|[binary]|
+--------+
... (WKB binary)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_cells")
result = df.select(bx.bng_aswkb(f.col("cellid")).alias("wkb")).first()
+--------+
|wkb |
+--------+
|[binary]|
+--------+
... (WKB binary)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_cells view (cellid = 'TQ3080', 1km cell, central London)
val df = spark.table("bng_cells")
val result = df.select(bx.bng_aswkb(col("cellid")).alias("wkb"))
result.show()
+--------+
|wkb |
+--------+
|[binary]|
+--------+
... (WKB binary)
bng_aswkt
LightweightHeavyweightConvert a BNG cell ID to Well-Known Text (WKT) format.
Powered by a pure-Python port of BNG.scala + shapely. The cell footprint as WKT in EPSG:27700 coordinates.
Signature: bng_aswkt(cellId: Column): Column
Parameters:
cellId- BNG cell reference string
Returns:
- String WKT geometry representation
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_aswkt('TQ3080') as wkt_geom;
+----------------------------------------------------------+
|wkt_geom |
+----------------------------------------------------------+
|POLYGON ((531000 180000, 531000 181000, 530000 181000, ...|
+----------------------------------------------------------+
POLYGON ((531000 180000, 531000 181000, 530000 181000, 530000 180000, 531000 180000))
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_cells_df(spark)
result = df.select(gx.bng_aswkt(f.col("cellid")).alias("wkt")).first()
+----------------------------------------------------------+
|wkt |
+----------------------------------------------------------+
|POLYGON ((531000 180000, 531000 181000, 530000 181000, ...|
+----------------------------------------------------------+
POLYGON ((531000 180000, 531000 181000, 530000 181000, 530000 180000, 531000 180000))
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_cells")
result = df.select(bx.bng_aswkt(f.col("cellid")).alias("wkt")).first()
+----------------------------------------------------------+
|wkt |
+----------------------------------------------------------+
|POLYGON ((531000 180000, 531000 181000, 530000 181000, ...|
+----------------------------------------------------------+
POLYGON ((531000 180000, 531000 181000, 530000 181000, 530000 180000, 531000 180000))
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_cells view (cellid = 'TQ3080')
val df = spark.table("bng_cells")
val result = df.select(bx.bng_aswkt(col("cellid")).alias("wkt"))
result.show(truncate = false)
+----------------------------------------------------------+
|wkt |
+----------------------------------------------------------+
|POLYGON ((531000 180000, 531000 181000, 530000 181000, ...|
+----------------------------------------------------------+
POLYGON ((531000 180000, 531000 181000, 530000 181000, 530000 180000, 531000 180000))
Core Functions
Fundamental operations on BNG cells.
bng_cellarea
LightweightHeavyweightCalculate the area of a BNG grid cell.
Powered by the pure-Python port of BNG.scala. Returns the cell area in square kilometres, matching the heavyweight tier.
Signature: bng_cellarea(cellId: Column): Column
Parameters:
cellId- BNG cell reference
Returns:
- Double representing the cell area in square kilometres
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_cellarea('TQ3080') AS area_km2;
+--------+
|area_km2|
+--------+
|1.0 |
+--------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_cells_df(spark)
result = df.select(gx.bng_cellarea(f.col("cellid")).alias("area_km2")).first()
+---------+
|area_km2 |
+---------+
|1.0 |
+---------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_cells")
result = df.select(bx.bng_cellarea(f.col("cellid")).alias("area_km2")).first()
+---------+
|area_km2 |
+---------+
|1.0 |
+---------+
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_cells view (cellid = 'TQ3080', a 1km cell → area = 1.0 sq km)
val df = spark.table("bng_cells")
val result = df.select(bx.bng_cellarea(col("cellid")).alias("area_km2"))
result.show()
+---------+
|area_km2 |
+---------+
|1.0 |
+---------+
bng_centroid
LightweightHeavyweightGet the centroid (center point) of a BNG cell.
Powered by the pure-Python port of BNG.scala + shapely. Cell-center POINT as WKB in EPSG:27700 (no SRID).
Signature: bng_centroid(cellId: Column): Column
Parameters:
cellId- BNG cell reference
Returns:
- Point geometry at cell center
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_centroid('TQ3080') as centroid;
+--------+
|centroid|
+--------+
|[binary]|
+--------+
... (WKB binary — POINT(530500 180500) in EPSG:27700)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_cells_df(spark)
result = df.select(gx.bng_centroid(f.col("cellid")).alias("centroid")).first()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (WKB binary — POINT(530500 180500) in EPSG:27700)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_cells")
result = df.select(bx.bng_centroid(f.col("cellid")).alias("centroid")).first()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (WKB binary — POINT(530500 180500) in EPSG:27700)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_cells view (cellid = 'TQ3080')
// Returns a WKB POINT at the cell centre (530500, 180500) in EPSG:27700
val df = spark.table("bng_cells")
val result = df.select(bx.bng_centroid(col("cellid")).alias("centroid"))
result.show()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (WKB binary — POINT(530500 180500) in EPSG:27700)
bng_distance
LightweightHeavyweightReturn the grid-step distance between two BNG cells.
Powered by the pure-Python port of BNG.scala — Chebyshev grid-step count between two cells, exact-parity with the heavyweight tier. Returns LONG (grid steps, not metres).
Signature: bng_distance(cellid1: Column, cellid2: Column): Column
Parameters:
cellid1- First BNG cell reference (STRING)cellid2- Second BNG cell reference (STRING)
Returns:
- LONG — Chebyshev grid-step distance. Adjacent cells (sharing an edge or corner) return 1; the cell itself returns 0.
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_distance('TQ3080', 'TQ3081') AS dist_steps;
+----------+
|dist_steps|
+----------+
|1 |
+----------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_cell_pairs_df(spark)
result = df.select(
gx.bng_distance(f.col("cellid1"), f.col("cellid2")).alias("dist_steps")
).first()
+----------+
|dist_steps|
+----------+
|1 |
+----------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_cell_pairs")
result = df.select(
bx.bng_distance(f.col("cellid1"), f.col("cellid2")).alias("dist_steps")
).first()
+----------+
|dist_steps|
+----------+
|1 |
+----------+
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_cell_pairs view (cellid1='TQ3080', cellid2='TQ3081', adjacent 1km cells)
// Returns LONG (grid steps, not metres): adjacent cells → dist_steps = 1
val df = spark.table("bng_cell_pairs")
val result = df.select(bx.bng_distance(col("cellid1"), col("cellid2")).alias("dist_steps"))
result.show()
+----------+
|dist_steps|
+----------+
|1 |
+----------+
bng_euclideandistance
LightweightHeavyweightReturn the Chebyshev grid-unit distance between two BNG cells.
Powered by the pure-Python port of BNG.scala — Chebyshev distance in grid units, exact-parity with the heavyweight tier. Returns LONG (grid units, not metres).
Signature: bng_euclideandistance(cellid1: Column, cellid2: Column): Column
Parameters:
cellid1- First BNG cell reference (STRING)cellid2- Second BNG cell reference (STRING)
Returns:
- LONG — Chebyshev distance in grid units. Adjacent cells return 1; diagonal cells also return 1.
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_euclideandistance('TQ3080', 'TQ3081') AS euclidean_dist;
+--------------+
|euclidean_dist|
+--------------+
|1 |
+--------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_cell_pairs_df(spark)
result = df.select(
gx.bng_euclideandistance(f.col("cellid1"), f.col("cellid2")).alias(
"euclidean_dist"
)
).first()
+--------------+
|euclidean_dist|
+--------------+
|1 |
+--------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_cell_pairs")
result = df.select(
bx.bng_euclideandistance(f.col("cellid1"), f.col("cellid2")).alias(
"euclidean_dist"
)
).first()
+--------------+
|euclidean_dist|
+--------------+
|1 |
+--------------+
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_cell_pairs view (cellid1='TQ3080', cellid2='TQ3081')
// Returns LONG (Chebyshev grid units): adjacent cells → euclidean_dist = 1
val df = spark.table("bng_cell_pairs")
val result = df.select(
bx.bng_euclideandistance(col("cellid1"), col("cellid2")).alias("euclidean_dist")
)
result.show()
+--------------+
|euclidean_dist|
+--------------+
|1 |
+--------------+
Cell Operations
Operations combining multiple BNG chip structs.
bng_cellintersection and bng_cellunion take STRUCT<cellid STRING, core BOOLEAN, chip BINARY> chip inputs — the same struct produced by bng_tessellate / bng_tessellateexplode. Passing plain STRING cell IDs throws ClassCastException. Use bng_tessellate(geom, resolution) to produce chip inputs.
bng_cellintersection
LightweightHeavyweightIntersect two BNG chip structs and return the dissolved intersection chip.
Powered by the pure-Python port of BNG.scala + shapely. Returns the same STRUCT<cellid, core, chip> as the heavyweight tier (AGREE).
Signature: bng_cellintersection(chip1: Column, chip2: Column): Column
Parameters:
chip1- First chip struct (STRUCT<cellid STRING, core BOOLEAN, chip BINARY>)chip2- Second chip struct (same schema)
Returns:
STRUCT<cellid STRING, core BOOLEAN, chip BINARY>— dissolved intersection chip. A fully interior chip (core=true) intersected with itself returns{cellid, true, null}.
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_cellintersection(chip, chip) AS intersection_chip
FROM (
SELECT explode(
gbx_bng_tessellate(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))', 3
)
) AS chip
) t
WHERE t.chip.cellid = 'TQ3080';
+--------------------+
|intersection_chip |
+--------------------+
|{TQ3080, true, null}|
+--------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_chips_df(spark)
result = (
df.filter(f.col("chip.cellid") == "TQ3080")
.select(
gx.bng_cellintersection(f.col("chip"), f.col("chip")).alias(
"intersection_chip"
)
)
.first()
)
+--------------------+
|intersection_chip |
+--------------------+
|{TQ3080, true, null}|
+--------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_chips")
result = (
df.filter(f.col("chip.cellid") == "TQ3080")
.select(
bx.bng_cellintersection(f.col("chip"), f.col("chip")).alias(
"intersection_chip"
)
)
.first()
)
+--------------------+
|intersection_chip |
+--------------------+
|{TQ3080, true, null}|
+--------------------+
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_chips view (9 chip structs from tessellating the BNG polygon at res=3)
// Filters for the core chip (TQ3080, core=true, chip=null) and intersects it with itself.
// Chip inputs must come from bng_tessellate — plain String cell IDs throw ClassCastException.
val df = spark.table("bng_chips").filter(col("chip.cellid") === "TQ3080")
val result = df.select(
bx.bng_cellintersection(col("chip"), col("chip")).alias("intersection_chip")
)
result.show()
+--------------------+
|intersection_chip |
+--------------------+
|{TQ3080, true, null}|
+--------------------+
bng_cellunion
LightweightHeavyweightUnion two BNG chip structs and return the dissolved union chip.
Powered by the pure-Python port of BNG.scala + shapely. Returns the same STRUCT<cellid, core, chip> as the heavyweight tier (AGREE).
Signature: bng_cellunion(chip1: Column, chip2: Column): Column
Parameters:
chip1- First chip struct (STRUCT<cellid STRING, core BOOLEAN, chip BINARY>)chip2- Second chip struct (same schema)
Returns:
STRUCT<cellid STRING, core BOOLEAN, chip BINARY>— dissolved union chip. A fully interior chip (core=true) unioned with itself returns{cellid, true, null}.
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_cellunion(chip, chip) AS union_chip
FROM (
SELECT explode(
gbx_bng_tessellate(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))', 3
)
) AS chip
) t
WHERE t.chip.cellid = 'TQ3080';
+--------------------+
|union_chip |
+--------------------+
|{TQ3080, true, null}|
+--------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_chips_df(spark)
result = (
df.filter(f.col("chip.cellid") == "TQ3080")
.select(gx.bng_cellunion(f.col("chip"), f.col("chip")).alias("union_chip"))
.first()
)
+--------------------+
|union_chip |
+--------------------+
|{TQ3080, true, null}|
+--------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_chips")
result = (
df.filter(f.col("chip.cellid") == "TQ3080")
.select(bx.bng_cellunion(f.col("chip"), f.col("chip")).alias("union_chip"))
.first()
)
+--------------------+
|union_chip |
+--------------------+
|{TQ3080, true, null}|
+--------------------+
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_chips view (9 chip structs from tessellating the BNG polygon at res=3)
// Filters for the core chip (TQ3080, core=true, chip=null) and unions it with itself.
// Chip inputs must come from bng_tessellate — plain String cell IDs throw ClassCastException.
val df = spark.table("bng_chips").filter(col("chip.cellid") === "TQ3080")
val result = df.select(
bx.bng_cellunion(col("chip"), col("chip")).alias("union_chip")
)
result.show()
+--------------------+
|union_chip |
+--------------------+
|{TQ3080, true, null}|
+--------------------+
Coordinate Conversion Functions
Convert coordinates or geometries to BNG cells.
bng_eastnorthasbng
LightweightHeavyweightConvert easting/northing coordinates to a BNG cell reference.
Powered by the pure-Python port of BNG.scala (numpy-vectorized encoder). Eastings/northings must be EPSG:27700 (e.g. 530000, 180000 for London). Bit-identical cell IDs to the heavyweight tier.
Signature: bng_eastnorthasbng(easting: Column, northing: Column, resolution: Column): Column
Parameters:
easting- Easting coordinate valuenorthing- Northing coordinate valueresolution- BNG resolution: integer index (1–6 or negative for quadrant) or string (e.g. '1km', '100m'). See resolutionMap in BNG.
Returns:
- String BNG cell reference
- SQL
- Python (light)
- Python (heavy)
- Scala
-- Convert OS Grid Reference coordinates (easting, northing); resolution '1km' or integer 3
SELECT gbx_bng_eastnorthasbng(530000, 180000, '1km') as bng_cell;
+--------+
|bng_cell|
+--------+
|TQ3080 |
+--------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_coordinates_df(spark)
result = df.select(
gx.bng_eastnorthasbng(f.col("easting"), f.col("northing"), f.lit("1km")).alias(
"bng_cell"
)
).first()
+--------+
|bng_cell|
+--------+
|TQ3080 |
+--------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_points")
result = df.select(
bx.bng_eastnorthasbng(f.col("easting"), f.col("northing"), f.lit("1km")).alias(
"bng_cell"
)
).first()
+--------+
|bng_cell|
+--------+
|TQ3080 |
+--------+
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_points view (easting=530000, northing=180000, EPSG:27700)
val df = spark.table("bng_points")
val result = df.select(
bx.bng_eastnorthasbng(col("easting"), col("northing"), lit("1km")).alias("bng_cell")
)
result.show()
+--------+
|bng_cell|
+--------+
|TQ3080 |
+--------+
bng_pointascell
LightweightHeavyweightConvert a point geometry to a BNG grid cell. The point must be supplied as WKT or WKB (GeoBrix does not accept native Databricks geometry types).
Powered by the pure-Python port of BNG.scala + shapely. The point coordinates must be EPSG:27700 eastings/northings (e.g. POINT(530000 180000) for London), not WGS84 lon/lat. Exact-parity cell IDs with the heavyweight tier.
Signature: bng_pointascell(point: Column, resolution: Column): Column
Parameters:
point- Point geometry as WKT (string) or WKB (binary). Must be in EPSG:27700 eastings/northings (e.g.'POINT(530000 180000)'for London). Do not usest_point()or other DBR native geometry functions — they return a type GeoBrix does not accept.resolution- BNG resolution: integer index (e.g. 3 for 1 km) or string (e.g. '1km', '100m')
Returns:
- String BNG cell reference
- SQL
- Python (light)
- Python (heavy)
- Scala
-- Point in BNG coordinates (eastings, northings); resolution '1km' for 1 km cell
SELECT gbx_bng_pointascell('POINT(530000 180000)', '1km') AS bng_cell;
+--------+
|bng_cell|
+--------+
|TQ3080 |
+--------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_coordinates_df(spark)
result = df.select(
gx.bng_pointascell(f.col("geom"), f.lit("1km")).alias("bng_cell")
).first()
+--------+
|bng_cell|
+--------+
|TQ3080 |
+--------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_points")
result = df.select(
bx.bng_pointascell(f.col("geom"), f.lit("1km")).alias("bng_cell")
).first()
+--------+
|bng_cell|
+--------+
|TQ3080 |
+--------+
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_points view (geom = 'POINT(530000 180000)' in EPSG:27700)
val df = spark.table("bng_points")
val result = df.select(
bx.bng_pointascell(col("geom"), lit("1km")).alias("bng_cell")
)
result.show()
+--------+
|bng_cell|
+--------+
|TQ3080 |
+--------+
K-Ring Functions
Generate neighboring cells using k-ring patterns.
bng_kring
LightweightHeavyweightGenerate a k-ring of cells around a center cell (filled disk).
Powered by the pure-Python port of BNG.scala. All cells within ring distance k (inclusive of the center). Exact cell-set parity with the heavyweight tier.
Signature: bng_kring(cellId: Column, k: Column): Column
Parameters:
cellId- BNG cell reference for centerk- Integer ring distance (0 = just center, 1 = center + neighbors, etc.)
Returns:
- Array of BNG cell references in the k-ring
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_kring('TQ3080', 1) AS kring;
+-----------------------------+
|kring |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (9 cells: center TQ3080 plus 8 surrounding cells at k=1)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_cells_df(spark)
result = df.select(gx.bng_kring(f.col("cellid"), f.lit(1)).alias("kring")).first()
+-----------------------------+
|kring |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (9 cells: center TQ3080 plus 8 surrounding cells at k=1)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_cells")
result = df.select(bx.bng_kring(f.col("cellid"), f.lit(1)).alias("kring")).first()
+-----------------------------+
|kring |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (9 cells: center TQ3080 plus 8 surrounding cells at k=1)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_cells view (cellid = 'TQ3080', 1km cell, central London)
// Returns ARRAY<STRING> — center plus 8 surrounding cells at k=1 → 9 cells
val df = spark.table("bng_cells")
val result = df.select(bx.bng_kring(col("cellid"), lit(1)).alias("kring"))
result.show(truncate = false)
+-----------------------------+
|kring |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (9 cells: center TQ3080 plus 8 surrounding cells at k=1)
bng_kloop
LightweightHeavyweightGenerate a k-loop of cells around a center cell (hollow ring).
Powered by the pure-Python port of BNG.scala. The cells at exactly ring distance k. Exact cell-set parity with the heavyweight tier.
Signature: bng_kloop(cellId: Column, k: Column): Column
Parameters:
cellId- BNG cell reference for centerk- Integer ring distance
Returns:
- Array of BNG cell references at exactly distance k
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_kloop('TQ3080', 1) AS kloop;
+-----------------------------+
|kloop |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (8 cells: hollow ring at k=1, center TQ3080 excluded)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_cells_df(spark)
result = df.select(gx.bng_kloop(f.col("cellid"), f.lit(1)).alias("kloop")).first()
+-----------------------------+
|kloop |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (8 cells: hollow ring at k=1, center TQ3080 excluded)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_cells")
result = df.select(bx.bng_kloop(f.col("cellid"), f.lit(1)).alias("kloop")).first()
+-----------------------------+
|kloop |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (8 cells: hollow ring at k=1, center TQ3080 excluded)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_cells view (cellid = 'TQ3080', 1km cell, central London)
// Returns ARRAY<STRING> — the 8 surrounding cells at k=1 (center excluded)
val df = spark.table("bng_cells")
val result = df.select(bx.bng_kloop(col("cellid"), lit(1)).alias("kloop"))
result.show(truncate = false)
+-----------------------------+
|kloop |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (8 cells: hollow ring at k=1, center TQ3080 excluded)
bng_geomkring
LightweightHeavyweightGenerate a k-ring of cells around a geometry at specified resolution.
Powered by the pure-Python port of BNG.scala + shapely. Polyfills the geometry then expands by ring distance k. Exact cell-set parity with the heavyweight tier.
Signature: bng_geomkring(geom: Column, resolution: Column, k: Column): Column
Parameters:
geom- Input geometry (any type)resolution- BNG resolution: integer index (e.g. 3 for 1 km) or string (e.g. '1km', '100m')k- Integer ring distance
Returns:
- Array of BNG cell references
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_geomkring(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))',
3, 1
) AS kring;
+-----------------------------+
|kring |
+-----------------------------+
|[TQ2878, TQ2879, TQ2880, ...]|
+-----------------------------+
... (25 cells: polyfill of BNG polygon expanded by k=1 ring)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_polygons_df(spark)
result = df.select(
gx.bng_geomkring(f.col("geom"), f.lit(3), f.lit(1)).alias("kring")
).first()
+-----------------------------+
|kring |
+-----------------------------+
|[TQ2878, TQ2879, TQ2880, ...]|
+-----------------------------+
... (25 cells: polyfill of BNG polygon expanded by k=1 ring)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_polygons")
result = df.select(
bx.bng_geomkring(f.col("geom"), f.lit(3), f.lit(1)).alias("kring")
).first()
+-----------------------------+
|kring |
+-----------------------------+
|[TQ2878, TQ2879, TQ2880, ...]|
+-----------------------------+
... (25 cells: polyfill of BNG polygon expanded by k=1 ring)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_polygons view (3km × 3km BNG polygon in EPSG:27700)
// EPSG:27700 coordinates required — WGS84 yields empty arrays
// res=3 polyfill → 9 cells; k=1 expansion → 25 cells total
val df = spark.table("bng_polygons")
val result = df.select(bx.bng_geomkring(col("geom"), lit(3), lit(1)).alias("kring"))
result.show(truncate = false)
+-----------------------------+
|kring |
+-----------------------------+
|[TQ2878, TQ2879, TQ2880, ...]|
+-----------------------------+
... (25 cells: polyfill of BNG polygon expanded by k=1 ring)
bng_geomkloop
LightweightHeavyweightGenerate a k-loop of cells around a geometry at specified resolution.
Powered by the pure-Python port of BNG.scala + shapely. Polyfills the geometry then returns only the cells at exactly ring distance k. Exact cell-set parity with the heavyweight tier.
Signature: bng_geomkloop(geom: Column, resolution: Column, k: Column): Column
Parameters:
geom- Input geometry (any type)resolution- BNG resolution: integer index (e.g. 3 for 1 km) or string (e.g. '1km', '100m')k- Integer ring distance
Returns:
- Array of BNG cell references at exactly distance k
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_geomkloop(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))',
3, 1
) AS kloop;
+-----------------------------+
|kloop |
+-----------------------------+
|[TQ2878, TQ2879, TQ2880, ...]|
+-----------------------------+
... (16 cells: outer ring at k=1 around the BNG polygon polyfill)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_polygons_df(spark)
result = df.select(
gx.bng_geomkloop(f.col("geom"), f.lit(3), f.lit(1)).alias("kloop")
).first()
+-----------------------------+
|kloop |
+-----------------------------+
|[TQ2878, TQ2879, TQ2880, ...]|
+-----------------------------+
... (16 cells: outer ring at k=1 around the BNG polygon polyfill)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_polygons")
result = df.select(
bx.bng_geomkloop(f.col("geom"), f.lit(3), f.lit(1)).alias("kloop")
).first()
+-----------------------------+
|kloop |
+-----------------------------+
|[TQ2878, TQ2879, TQ2880, ...]|
+-----------------------------+
... (16 cells: outer ring at k=1 around the BNG polygon polyfill)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_polygons view (3km × 3km BNG polygon in EPSG:27700)
// EPSG:27700 coordinates required — WGS84 yields empty arrays
// res=3 polyfill → 9 cells; k=1 outer ring → 16 cells (hollow shell)
val df = spark.table("bng_polygons")
val result = df.select(bx.bng_geomkloop(col("geom"), lit(3), lit(1)).alias("kloop"))
result.show(truncate = false)
+-----------------------------+
|kloop |
+-----------------------------+
|[TQ2878, TQ2879, TQ2880, ...]|
+-----------------------------+
... (16 cells: outer ring at k=1 around the BNG polygon polyfill)
Tessellation Functions
Fill geometries with grid cells.
bng_polyfill
LightweightHeavyweightFill a geometry with BNG cells at specified resolution.
Powered by the pure-Python port of BNG.scala + shapely. Enumerates the cells covering the geometry, mirroring the heavyweight seed-and-flood-fill. Exact cell-set parity with the heavyweight tier.
Signature: bng_polyfill(geometry: Column, resolution: Column): Column
Parameters:
geometry- Input geometry to fillresolution- BNG resolution: integer index (e.g. 3 for 1 km) or string (e.g. '1km', '100m')
Returns:
- Array of BNG cell IDs covering the geometry
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_polyfill(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))',
3
) AS cells;
+-----------------------------+
|cells |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (9 cells covering the 3km × 3km BNG polygon at 1km resolution)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_polygons_df(spark)
result = df.select(gx.bng_polyfill(f.col("geom"), f.lit(3)).alias("cells")).first()
+-----------------------------+
|cells |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (9 cells covering the 3km × 3km BNG polygon at 1km resolution)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_polygons")
result = df.select(bx.bng_polyfill(f.col("geom"), f.lit(3)).alias("cells")).first()
+-----------------------------+
|cells |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (9 cells covering the 3km × 3km BNG polygon at 1km resolution)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_polygons view (3km × 3km BNG polygon in EPSG:27700)
// EPSG:27700 coordinates required — WGS84 yields empty arrays
// res=3 (1km cells): 9 cells cover the 3km × 3km polygon
val df = spark.table("bng_polygons")
val result = df.select(bx.bng_polyfill(col("geom"), lit(3)).alias("cells"))
result.show(truncate = false)
+-----------------------------+
|cells |
+-----------------------------+
|[TQ2979, TQ2980, TQ2981, ...]|
+-----------------------------+
... (9 cells covering the 3km × 3km BNG polygon at 1km resolution)
bng_tessellate
LightweightHeavyweightTessellate a geometry into BNG cells with their geometries.
Powered by the pure-Python port of BNG.scala + shapely. Polyfill plus a per-cell core/border split, returning one STRUCT<cellid, core, chip> per cell (chip geometry as WKB in EPSG:27700, no SRID). Border chips are filtered to the input geometry type, matching the heavyweight tier.
Signature: bng_tessellate(geometry: Column, resolution: Column): Column
Parameters:
geometry- Input geometry to tessellateresolution- BNG resolution: integer index (e.g. 3 for 1 km) or string (e.g. '1km', '100m')
Returns:
- Array of structs containing cell ID and geometry
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_bng_tessellate(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))',
3
) AS chips;
+--------------------------------------------+
|chips |
+--------------------------------------------+
|[{TQ2979, false, [binary]}, {TQ3080, true,..|
+--------------------------------------------+
... (9 chips; TQ3080 is core (core=true, chip=null); border cells carry WKB clip geometry)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_polygons_df(spark)
result = df.select(
gx.bng_tessellate(f.col("geom"), f.lit(3)).alias("chips")
).first()
+--------------------------------------------+
|chips |
+--------------------------------------------+
|[{TQ2979, false, [binary]}, {TQ3080, true,..|
+--------------------------------------------+
... (9 chips; TQ3080 is core (core=true, chip=null); border cells carry WKB clip geometry)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
df = spark.table("bng_polygons")
result = df.select(
bx.bng_tessellate(f.col("geom"), f.lit(3)).alias("chips")
).first()
+--------------------------------------------+
|chips |
+--------------------------------------------+
|[{TQ2979, false, [binary]}, {TQ3080, true,..|
+--------------------------------------------+
... (9 chips; TQ3080 is core (core=true, chip=null); border cells carry WKB clip geometry)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_polygons view (3km × 3km BNG polygon in EPSG:27700)
// EPSG:27700 coordinates required — WGS84 yields empty arrays
// res=3 (1km): 9 chips; TQ3080 is core (core=true, chip=null); borders carry WKB clip
val df = spark.table("bng_polygons")
val result = df.select(bx.bng_tessellate(col("geom"), lit(3)).alias("chips"))
result.show(truncate = false)
+--------------------------------------------+
|chips |
+--------------------------------------------+
|[{TQ2979, false, [binary]}, {TQ3080, true,..|
+--------------------------------------------+
... (9 chips; TQ3080 is core (core=true, chip=null); border cells carry WKB clip geometry)
Aggregator Functions
Aggregate multiple cells into a single result.
bng_cellintersection_agg
LightweightHeavyweight Grouped-agg UDFAggregate intersection of multiple BNG cells.
Powered by the pure-Python port of BNG.scala + shapely. A grouped aggregate — groupBy(cellid).agg(gx.bng_cellintersection_agg("chip")) intersects a group's chips (all belonging to one cell) into the dissolved chip geometry.
Heavyweight gbx_bng_cellintersection_agg returns a chip STRUCT<cellid, core, chip>; the lightweight function returns BINARY (the dissolved chip geometry, WKB in EPSG:27700) in both Python and SQL. A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight aggregate emits the chip geometry — the one meaningful payload of a dissolved aggregate. The aggregate only ever combines chips from a single cell, so the heavyweight struct's cellid is exactly the group key you GROUP BY, and core is recoverable from whether the chip equals the full cell — neither carries information beyond the BINARY chip. To reconstruct the heavyweight STRUCT shape in SQL, project the group key as cellid:
-- Lightweight SQL: rebuild the (cellid, chip) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_bng_cellintersection_agg(chip) AS chip
FROM cells
GROUP BY group_key
Signature: bng_cellintersection_agg(cellId: Column): Column
Parameters:
cellId- BNG cell reference column to aggregate
Returns:
- BNG cell ID representing common intersection
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT t.chip.cellid, gbx_bng_cellintersection_agg(t.chip) AS common_chip
FROM (
SELECT explode(gbx_bng_tessellate(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))', 3
)) AS chip
) t
WHERE t.chip.cellid = 'TQ3080'
GROUP BY t.chip.cellid;
# Heavyweight SQL (active tier = heavy/Scala) — STRUCT<cellid, core, chip>:
+------+--------------------+
|cellid|common_chip |
+------+--------------------+
|TQ3080|{TQ3080, true, null}|
+------+--------------------+
... (core cell TQ3080: chip=null means the full cell polygon)
# Lightweight SQL (active tier = pygx) — BINARY (dissolved chip WKB in EPSG:27700):
+------+-----------+
|cellid|common_chip|
+------+-----------+
|TQ3080|[binary] |
+------+-----------+
... (core cell TQ3080: [binary] is the WKB of the full TQ3080 polygon)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_chips_df(spark)
df_keyed = df.select(
f.col("chip"),
f.col("chip.cellid").alias("cellid"),
)
result = (
df_keyed.groupBy("cellid")
.agg(gx.bng_cellintersection_agg("chip").alias("common_chip"))
.filter(f.col("cellid") == "TQ3080")
.first()
)
+-------+------------+
|cellid |common_chip |
+-------+------------+
|TQ3080 |[binary] |
+-------+------------+
... (BINARY — dissolved chip WKB for TQ3080; core cell → full cell polygon in EPSG:27700)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
bx.register(spark) # ensure the heavy (STRUCT-returning) BNG tier is registered
df = spark.table("bng_chips")
df_keyed = df.select(
f.col("chip"),
f.col("chip.cellid").alias("cellid"),
)
result = (
df_keyed.groupBy("cellid")
.agg(bx.bng_cellintersection_agg("chip").alias("common_chip"))
.filter(f.col("cellid") == "TQ3080")
.first()
)
+-------+--------------------+
|cellid |common_chip |
+-------+--------------------+
|TQ3080 |{TQ3080, true, null}|
+-------+--------------------+
... (STRUCT — heavy tier returns chip struct; TQ3080 core chip: cellid=TQ3080, core=true, chip=null)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_chips view (9 chip structs from tessellating the BNG polygon at res=3)
// Groups by chip.cellid and intersects chips within each group.
// Each group holds exactly one chip — the aggregate returns that chip unchanged.
// Heavy tier returns STRUCT<cellid, core, chip>; light returns BINARY.
val df = spark.table("bng_chips").select(
col("chip"),
col("chip.cellid").alias("cellid")
)
val result = df.groupBy("cellid")
.agg(bx.bng_cellintersection_agg(col("chip")).alias("common_chip"))
.filter(col("cellid") === "TQ3080")
result.show(truncate = false)
+------+--------------------+
|cellid|common_chip |
+------+--------------------+
|TQ3080|{TQ3080, true, null}|
+------+--------------------+
... (STRUCT — TQ3080 core chip: cellid=TQ3080, core=true, chip=null)
bng_cellunion_agg
LightweightHeavyweight Grouped-agg UDFAggregate union of multiple BNG cells.
Powered by the pure-Python port of BNG.scala + shapely. A grouped aggregate — groupBy(cellid).agg(gx.bng_cellunion_agg("chip")) dissolves a group's chips (all belonging to one cell) into the unioned chip geometry.
Heavyweight gbx_bng_cellunion_agg returns a chip STRUCT<cellid, core, chip>; the lightweight function returns BINARY (the dissolved chip geometry, WKB in EPSG:27700) in both Python and SQL. A PySpark grouped-aggregate pandas_udf cannot return a StructType, so the lightweight aggregate emits the chip geometry — the one meaningful payload of a dissolved aggregate. The aggregate only ever combines chips from a single cell, so the heavyweight struct's cellid is exactly the group key you GROUP BY, and core is recoverable from whether the chip equals the full cell — neither carries information beyond the BINARY chip. To reconstruct the heavyweight STRUCT shape in SQL, project the group key as cellid:
-- Lightweight SQL: rebuild the (cellid, chip) the heavyweight struct would carry
SELECT
group_key AS cellid,
gbx_bng_cellunion_agg(chip) AS chip
FROM cells
GROUP BY group_key
Signature: bng_cellunion_agg(cellId: Column): Column
Parameters:
cellId- BNG cell reference column to aggregate
Returns:
- BNG cell ID representing bounding union
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT t.chip.cellid, gbx_bng_cellunion_agg(t.chip) AS union_chip
FROM (
SELECT explode(gbx_bng_tessellate(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))', 3
)) AS chip
) t
WHERE t.chip.cellid = 'TQ3080'
GROUP BY t.chip.cellid;
# Heavyweight SQL (active tier = heavy/Scala) — STRUCT<cellid, core, chip>:
+------+--------------------+
|cellid|union_chip |
+------+--------------------+
|TQ3080|{TQ3080, true, null}|
+------+--------------------+
... (core cell TQ3080: chip=null means the full cell polygon)
# Lightweight SQL (active tier = pygx) — BINARY (dissolved chip WKB in EPSG:27700):
+------+----------+
|cellid|union_chip|
+------+----------+
|TQ3080|[binary] |
+------+----------+
... (core cell TQ3080: [binary] is the WKB of the full TQ3080 polygon)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_bng_chips_df(spark)
df_keyed = df.select(
f.col("chip"),
f.col("chip.cellid").alias("cellid"),
)
result = (
df_keyed.groupBy("cellid")
.agg(gx.bng_cellunion_agg("chip").alias("union_chip"))
.filter(f.col("cellid") == "TQ3080")
.first()
)
+-------+----------+
|cellid |union_chip|
+-------+----------+
|TQ3080 |[binary] |
+-------+----------+
... (BINARY — dissolved chip WKB for TQ3080; core cell → full cell polygon in EPSG:27700)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.bng import functions as bx
bx.register(spark) # ensure the heavy (STRUCT-returning) BNG tier is registered
df = spark.table("bng_chips")
df_keyed = df.select(
f.col("chip"),
f.col("chip.cellid").alias("cellid"),
)
result = (
df_keyed.groupBy("cellid")
.agg(bx.bng_cellunion_agg("chip").alias("union_chip"))
.filter(f.col("cellid") == "TQ3080")
.first()
)
+-------+--------------------+
|cellid |union_chip |
+-------+--------------------+
|TQ3080 |{TQ3080, true, null}|
+-------+--------------------+
... (STRUCT — heavy tier returns chip struct; TQ3080 core chip: cellid=TQ3080, core=true, chip=null)
import com.databricks.labs.gbx.gridx.bng.{functions => bx}
import org.apache.spark.sql.functions._
// Reads the bng_chips view (9 chip structs from tessellating the BNG polygon at res=3)
// Groups by chip.cellid and dissolves chips within each group.
// Each group holds exactly one chip — the aggregate returns that chip unchanged.
// Heavy tier returns STRUCT<cellid, core, chip>; light returns BINARY.
val df = spark.table("bng_chips").select(
col("chip"),
col("chip.cellid").alias("cellid")
)
val result = df.groupBy("cellid")
.agg(bx.bng_cellunion_agg(col("chip")).alias("union_chip"))
.filter(col("cellid") === "TQ3080")
result.show(truncate = false)
+------+--------------------+
|cellid|union_chip |
+------+--------------------+
|TQ3080|{TQ3080, true, null}|
+------+--------------------+
... (STRUCT — TQ3080 core chip: cellid=TQ3080, core=true, chip=null)
Generator Functions
Explode array results into individual rows.
bng_kringexplode
LightweightHeavyweight Streaming UDTFExplode k-ring cells into separate rows.
Powered by the pure-Python port of BNG.scala as a streaming UDTF — one output row per k-ring cell. Exact cell-set parity with the heavyweight tier.
Signature: bng_kringexplode(cellId: Column, k: Column): Column
Parameters:
cellId- BNG cell reference for centerk- Integer ring distance
Returns:
- Exploded rows, one per cell in k-ring
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT t.*
FROM (SELECT 'TQ3080' AS cellid) src,
LATERAL gbx_bng_kringexplode(src.cellid, 1) t;
result = spark.sql("""
SELECT t.*
FROM (SELECT 'TQ3080' AS cellid) src,
LATERAL gbx_bng_kringexplode(src.cellid, 1) t
""")
+------+
|cellid|
+------+
|TQ2979|
|TQ2980|
|TQ2981|
|TQ3079|
|TQ3080|
|TQ3081|
|TQ3179|
|TQ3180|
|TQ3181|
+------+
... (9 rows: center TQ3080 plus 8 surrounding cells at k=1)
Not available in this tier.
Not available in this tier.
bng_kloopexplode
LightweightHeavyweight Streaming UDTFExplode k-loop cells into separate rows.
Powered by the pure-Python port of BNG.scala as a streaming UDTF — one output row per k-loop cell. Exact cell-set parity with the heavyweight tier.
Signature: bng_kloopexplode(cellId: Column, k: Column): Column
Parameters:
cellId- BNG cell reference for centerk- Integer ring distance
Returns:
- Exploded rows, one per cell in k-loop
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT t.*
FROM (SELECT 'TQ3080' AS cellid) src,
LATERAL gbx_bng_kloopexplode(src.cellid, 1) t;
result = spark.sql("""
SELECT t.*
FROM (SELECT 'TQ3080' AS cellid) src,
LATERAL gbx_bng_kloopexplode(src.cellid, 1) t
""")
+------+
|cellid|
+------+
|TQ2979|
|TQ2980|
|TQ2981|
|TQ3079|
|TQ3081|
|TQ3179|
|TQ3180|
|TQ3181|
+------+
... (8 rows: hollow ring at k=1, center TQ3080 excluded)
Not available in this tier.
Not available in this tier.
bng_geomkringexplode
LightweightHeavyweight Streaming UDTFExplode geometry k-ring cells into separate rows.
Powered by the pure-Python port of BNG.scala + shapely as a streaming UDTF — one output row per geometry k-ring cell. Exact cell-set parity with the heavyweight tier.
Signature: bng_geomkringexplode(geom: Column, resolution: Column, k: Column): Column
Parameters:
geom- Input geometryresolution- BNG resolution: integer index (e.g. 3 for 1 km) or string (e.g. '1km', '100m')k- Integer ring distance
Returns:
- Exploded rows, one per cell
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT t.*
FROM (SELECT 'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))' AS geom) src,
LATERAL gbx_bng_geomkringexplode(src.geom, 3, 1) t;
df = _get_bng_polygons_df(spark)
df.createOrReplaceTempView("_bng_polygons_tmp")
result = spark.sql(
"SELECT t.* FROM _bng_polygons_tmp src, "
"LATERAL gbx_bng_geomkringexplode(src.geom, 3, 1) t"
)
+------+
|cellid|
+------+
|TQ2878|
|TQ2879|
|TQ2880|
|... |
+------+
... (25 rows: polyfill of BNG polygon at res=3 expanded by k=1 ring)
Not available in this tier.
Not available in this tier.
bng_geomkloopexplode
LightweightHeavyweight Streaming UDTFExplode geometry k-loop cells into separate rows.
Powered by the pure-Python port of BNG.scala + shapely as a streaming UDTF — one output row per geometry k-loop cell. Exact cell-set parity with the heavyweight tier.
Signature: bng_geomkloopexplode(geom: Column, resolution: Column, k: Column): Column
Parameters:
geom- Input geometryresolution- BNG resolution: integer index (e.g. 3 for 1 km) or string (e.g. '1km', '100m')k- Integer ring distance
Returns:
- Exploded rows, one per cell at distance k
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT t.*
FROM (SELECT 'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))' AS geom) src,
LATERAL gbx_bng_geomkloopexplode(src.geom, 3, 1) t;
df = _get_bng_polygons_df(spark)
df.createOrReplaceTempView("_bng_polygons_tmp")
result = spark.sql(
"SELECT t.* FROM _bng_polygons_tmp src, "
"LATERAL gbx_bng_geomkloopexplode(src.geom, 3, 1) t"
)
+------+
|cellid|
+------+
|TQ2878|
|TQ2879|
|TQ2880|
|... |
+------+
... (16 rows: outer ring at k=1 around the BNG polygon polyfill)
Not available in this tier.
Not available in this tier.
bng_tessellateexplode
LightweightHeavyweight Streaming UDTFExplode tessellated cells into separate rows.
Powered by the pure-Python port of BNG.scala + shapely as a streaming UDTF — one output row per tessellated cell, each carrying the cell ID and chip geometry (WKB in EPSG:27700, no SRID).
Signature: bng_tessellateexplode(geometry: Column, resolution: Column): Column
Parameters:
geometry- Input geometry to tessellateresolution- BNG resolution: integer index (e.g. 3 for 1 km) or string (e.g. '1km', '100m')
Returns:
- Exploded rows with cell ID and geometry for each cell
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT t.*
FROM (SELECT 'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))' AS geom) src,
LATERAL gbx_bng_tessellateexplode(src.geom, 3) t;
df = _get_bng_polygons_df(spark)
df.createOrReplaceTempView("_bng_polygons_tmp")
result = spark.sql(
"SELECT t.* FROM _bng_polygons_tmp src, "
"LATERAL gbx_bng_tessellateexplode(src.geom, 3) t"
)
+------+-----+--------+
|cellid|core |chip |
+------+-----+--------+
|TQ2979|false|[binary]|
|TQ2980|false|[binary]|
|TQ2981|false|[binary]|
|TQ3079|false|[binary]|
|TQ3080|true |null |
|... |... |... |
+------+-----+--------+
... (9 rows; TQ3080 is core (core=true, chip=null); border cells carry WKB clip geometry)
Not available in this tier.
Not available in this tier.
BNG Reference Format
Standard Format
BNG references follow: [Letters][Eastings][Northings]
Common Resolutions
| Resolution | Grid Size | Example | Use Case |
|---|---|---|---|
| 100000m | 100km × 100km | TQ | Regional |
| 10000m | 10km × 10km | TQ38 | District |
| 1000m | 1km × 1km | TQ3080 | Local area |
| 100m | 100m × 100m | TQ308808 | Neighborhood |
| 10m | 10m × 10m | TQ30808080 | Building |
| 1m | 1m × 1m | TQ3080080800 | Precise location |
Major Grid Squares
Major 100km grid squares in Great Britain:
- TQ - London area
- SU - South Hampshire
- NT - Edinburgh area
- SD - Lake District
- ST - Bristol area
Custom Grid Functions
LightweightHeavyweight Custom-grid functions run in both tiers. The lightweight tier is the pygx custom-grid package — powered by a pure-Python port of the custom-grid system + shapely for geometry; identical gbx_custom_* SQL names, so it is a drop-in swap (no external grid library, unlike quadbin's quadbin package). Cell IDs are BIGINT values; geometry outputs are plain WKB with no SRID — the grid's srid is metadata only. Geometry inputs accept WKB, EWKB, WKT, or EWKT in both tiers. Cell-id math and cell sets are exact-parity with the heavyweight tier, enforced by the cross-tier parity suite. gbx_custom_grid returns the same descriptor struct in both tiers.
A custom grid is a user-defined regular rectangular grid specified by its spatial extent, root cell size, and a recursive split factor. Cell IDs are BIGINT values; hierarchy is controlled by cell_splits (each level subdivides root cells into cell_splits x cell_splits sub-cells). Use custom grids when neither BNG nor quadbin matches your coordinate reference system or cell-size requirements — for example, a national grid in EPSG:27700 with non-standard tile sizes.
custom_grid
LightweightHeavyweightDefine a user-specified regular grid from an origin, extent, cell size, split factor, and SRID.
Signature: gbx_custom_grid(boundXMin, boundXMax, boundYMin, boundYMax, cellSplits, rootCellSizeX, rootCellSizeY, srid)
Parameters:
boundXMin— minimum X bound of the grid extentboundXMax— maximum X bound of the grid extentboundYMin— minimum Y bound of the grid extentboundYMax— maximum Y bound of the grid extentcellSplits— number of splits per axis at each resolution level (e.g. 2 = 2x2 = 4 sub-cells per step)rootCellSizeX— root cell width in CRS unitsrootCellSizeY— root cell height in CRS unitssrid— spatial reference ID (e.g. 27700 for BNG)
Returns:
STRUCT<bound_x_min, bound_x_max, bound_y_min, bound_y_max, cell_splits, root_cell_size_x, root_cell_size_y, srid>— a grid descriptor struct passed to all othergbx_custom_*functions.
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_custom_grid(0, 1000000, 0, 1000000, 2, 1000, 1000, 27700) AS grid;
+----------------------------------------------+
|grid |
+----------------------------------------------+
|{0, 1000000, 0, 1000000, 2, 1000, 1000, 27700}|
+----------------------------------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
base = spark.sql("SELECT 1 AS dummy")
result = base.select(
gx.custom_grid(
f.lit(0),
f.lit(1000000),
f.lit(0),
f.lit(1000000),
f.lit(2),
f.lit(1000),
f.lit(1000),
f.lit(27700),
).alias("grid")
).first()
+----------------------------------------------+
|grid |
+----------------------------------------------+
|{0, 1000000, 0, 1000000, 2, 1000, 1000, 27700}|
+----------------------------------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.custom import functions as cx
base = spark.sql("SELECT 1 AS dummy")
result = base.select(
cx.custom_grid(
f.lit(0),
f.lit(1000000),
f.lit(0),
f.lit(1000000),
f.lit(2),
f.lit(1000),
f.lit(1000),
f.lit(27700),
).alias("grid")
).first()
+----------------------------------------------+
|grid |
+----------------------------------------------+
|{0, 1000000, 0, 1000000, 2, 1000, 1000, 27700}|
+----------------------------------------------+
import com.databricks.labs.gbx.gridx.custom.{functions => cx}
import org.apache.spark.sql.functions._
// Define a BNG-like custom grid: EPSG:27700, 1km root cells, 2 splits/level
val df = spark.sql("SELECT 1 AS dummy")
val result = df.select(
cx.custom_grid(
lit(0), lit(1000000), lit(0), lit(1000000),
lit(2), lit(1000), lit(1000), lit(27700)
).alias("grid")
)
result.show(truncate = false)
+----------------------------------------------+
|grid |
+----------------------------------------------+
|{0, 1000000, 0, 1000000, 2, 1000, 1000, 27700}|
+----------------------------------------------+
custom_pointascell
LightweightHeavyweightIndex a point geometry into a custom grid cell ID at the specified resolution level.
Signature: gbx_custom_pointascell(point, grid, resolution)
Parameters:
point— point geometry as WKT (STRING) or WKB (BINARY) in the grid's CRSgrid— custom grid descriptor returned bygbx_custom_gridresolution— resolution level (integer; 0 = root cells, higher = finer)
Returns:
BIGINTcell ID encoding the grid position at the given resolution
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_custom_pointascell('POINT(530000 180000)', gbx_custom_grid(0, 1000000, 0, 1000000, 2, 1000, 1000, 27700), 5) AS cell;
+------------------+
|cell |
+------------------+
|360287970373976640|
+------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_custom_grid_df(spark)
result = df.select(
gx.custom_pointascell(f.col("point"), f.col("grid"), f.lit(5)).alias("cell")
).first()
+--------------------+
|cell |
+--------------------+
|360287970373976640 |
+--------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.custom import functions as cx
df = spark.table("custom_grids")
result = df.select(
cx.custom_pointascell(f.col("point"), f.col("grid"), f.lit(5)).alias("cell")
).first()
+--------------------+
|cell |
+--------------------+
|360287970373976640 |
+--------------------+
import com.databricks.labs.gbx.gridx.custom.{functions => cx}
import org.apache.spark.sql.functions._
// Reads the custom_grids view (point = 'POINT(530000 180000)', grid struct, EPSG:27700)
// Resolution 5 maps the easting/northing to cell 360287970373976640
val df = spark.table("custom_grids")
val result = df.select(
cx.custom_pointascell(col("point"), col("grid"), lit(5)).alias("cell")
)
result.show()
+--------------------+
|cell |
+--------------------+
|360287970373976640 |
+--------------------+
custom_cellaswkb
LightweightHeavyweightReturn the WKB footprint polygon of a custom grid cell.
Signature: gbx_custom_cellaswkb(cell, grid)
Parameters:
cell—BIGINTcell IDgrid— custom grid descriptor returned bygbx_custom_grid
Returns:
BINARYWKB polygon representing the cell boundary (geometry... (WKB binary))
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_custom_cellaswkb(360287970373976640, gbx_custom_grid(0, 1000000, 0, 1000000, 2, 1000, 1000, 27700)) AS geom;
+--------+
|geom |
+--------+
|[binary]|
+--------+
... (WKB binary — 31.25m × 31.25m custom grid cell footprint polygon)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_custom_grid_df(spark)
result = df.select(
gx.custom_cellaswkb(f.col("cell"), f.col("grid")).alias("geom")
).first()
+--------+
|geom |
+--------+
|[binary]|
+--------+
... (WKB binary — 31.25m × 31.25m custom grid cell footprint polygon)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.custom import functions as cx
df = spark.table("custom_grids")
result = df.select(
cx.custom_cellaswkb(f.col("cell"), f.col("grid")).alias("geom")
).first()
+--------+
|geom |
+--------+
|[binary]|
+--------+
... (WKB binary — 31.25m × 31.25m custom grid cell footprint polygon)
import com.databricks.labs.gbx.gridx.custom.{functions => cx}
import org.apache.spark.sql.functions._
// Reads the custom_grids view (cell = 360287970373976640 at res=5, grid struct)
// Returns the 31.25m x 31.25m cell footprint polygon as plain WKB (no SRID)
val df = spark.table("custom_grids")
val result = df.select(cx.custom_cellaswkb(col("cell"), col("grid")).alias("geom"))
result.show()
+--------+
|geom |
+--------+
|[binary]|
+--------+
... (WKB binary — 31.25m × 31.25m custom grid cell footprint polygon)
custom_cellaswkt
LightweightHeavyweightReturn the WKT footprint polygon of a custom grid cell.
Signature: gbx_custom_cellaswkt(cell, grid)
Parameters:
cell—BIGINTcell IDgrid— custom grid descriptor returned bygbx_custom_grid
Returns:
STRINGWKT polygon representing the cell boundary
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_custom_cellaswkt(360287970373976640, gbx_custom_grid(0, 1000000, 0, 1000000, 2, 1000, 1000, 27700)) AS wkt;
+----------------------------------------------------------------------------------------------------+
|wkt |
+----------------------------------------------------------------------------------------------------+
|POLYGON ((530031.25 180000, 530031.25 180031.25, 530000 180031.25, 530000 180000, 530031.25 180000))|
+----------------------------------------------------------------------------------------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_custom_grid_df(spark)
result = df.select(
gx.custom_cellaswkt(f.col("cell"), f.col("grid")).alias("wkt")
).first()
+----------------------------------------------------------------------------------------------------+
|wkt |
+----------------------------------------------------------------------------------------------------+
|POLYGON ((530031.25 180000, 530031.25 180031.25, 530000 180031.25, 530000 180000, 530031.25 180000))|
+----------------------------------------------------------------------------------------------------+
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.custom import functions as cx
df = spark.table("custom_grids")
result = df.select(
cx.custom_cellaswkt(f.col("cell"), f.col("grid")).alias("wkt")
).first()
+----------------------------------------------------------------------------------------------------+
|wkt |
+----------------------------------------------------------------------------------------------------+
|POLYGON ((530031.25 180000, 530031.25 180031.25, 530000 180031.25, 530000 180000, 530031.25 180000))|
+----------------------------------------------------------------------------------------------------+
import com.databricks.labs.gbx.gridx.custom.{functions => cx}
import org.apache.spark.sql.functions._
// Reads the custom_grids view (cell = 360287970373976640 at res=5, grid struct)
// Returns the cell boundary as a WKT POLYGON in EPSG:27700 coordinates
val df = spark.table("custom_grids")
val result = df.select(cx.custom_cellaswkt(col("cell"), col("grid")).alias("wkt"))
result.show(truncate = false)
+----------------------------------------------------------------------------------------------------+
|wkt |
+----------------------------------------------------------------------------------------------------+
|POLYGON ((530031.25 180000, 530031.25 180031.25, 530000 180031.25, 530000 180000, 530031.25 180000))|
+----------------------------------------------------------------------------------------------------+
custom_centroid
LightweightHeavyweightReturn the centroid of a custom grid cell as a WKB point.
Signature: gbx_custom_centroid(cell, grid)
Parameters:
cell—BIGINTcell IDgrid— custom grid descriptor returned bygbx_custom_grid
Returns:
BINARYWKB point at the cell center (geometry... (WKB binary))
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_custom_centroid(360287970373976640, gbx_custom_grid(0, 1000000, 0, 1000000, 2, 1000, 1000, 27700)) AS centroid;
+--------+
|centroid|
+--------+
|[binary]|
+--------+
... (WKB binary — POINT at the center of the 31.25m × 31.25m custom grid cell)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_custom_grid_df(spark)
result = df.select(
gx.custom_centroid(f.col("cell"), f.col("grid")).alias("centroid")
).first()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (WKB binary — POINT at the center of the 31.25m × 31.25m custom grid cell)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.custom import functions as cx
df = spark.table("custom_grids")
result = df.select(
cx.custom_centroid(f.col("cell"), f.col("grid")).alias("centroid")
).first()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (WKB binary — POINT at the center of the 31.25m × 31.25m custom grid cell)
import com.databricks.labs.gbx.gridx.custom.{functions => cx}
import org.apache.spark.sql.functions._
// Reads the custom_grids view (cell = 360287970373976640 at res=5, grid struct)
// Returns the center of the 31.25m x 31.25m cell as plain WKB (no SRID)
val df = spark.table("custom_grids")
val result = df.select(cx.custom_centroid(col("cell"), col("grid")).alias("centroid"))
result.show()
+-----------+
|centroid |
+-----------+
|[binary] |
+-----------+
... (WKB binary — POINT at the center of the 31.25m × 31.25m custom grid cell)
custom_polyfill
LightweightHeavyweightFill a geometry with all custom grid cell IDs at the specified resolution.
Signature: gbx_custom_polyfill(geom, grid, resolution)
Parameters:
geom— input geometry as WKT (STRING) or WKB (BINARY) in the grid's CRSgrid— custom grid descriptor returned bygbx_custom_gridresolution— resolution level (integer; higher = finer cells)
Returns:
ARRAY<BIGINT>of cell IDs whose footprints intersect the geometry
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_custom_polyfill('POLYGON((529000 179000,529000 182000,532000 182000,532000 179000,529000 179000))', gbx_custom_grid(0, 1000000, 0, 1000000, 2, 1000, 1000, 27700), 1) AS cells;
+---------------------------------------------+
|cells |
+---------------------------------------------+
|[72057594038644994, ..., (36 cells at res=1)]|
+---------------------------------------------+
... (36 BIGINT cell IDs — 500m cells covering the 3km × 3km BNG polygon at resolution 1)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_custom_grid_df(spark)
result = df.select(
gx.custom_polyfill(f.lit(_BNG_POLY_WKT), f.col("grid"), f.lit(1)).alias("cells")
).first()
+---------------------------------------------+
|cells |
+---------------------------------------------+
|[72057594038644994, ..., (36 cells at res=1)]|
+---------------------------------------------+
... (36 BIGINT cell IDs — 500m cells covering the 3km × 3km BNG polygon at resolution 1)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.custom import functions as cx
df = spark.table("custom_grids")
result = df.select(
cx.custom_polyfill(f.lit(_CUSTOM_BNG_POLY_WKT), f.col("grid"), f.lit(1)).alias(
"cells"
)
).first()
+---------------------------------------------+
|cells |
+---------------------------------------------+
|[72057594038644994, ..., (36 cells at res=1)]|
+---------------------------------------------+
... (36 BIGINT cell IDs — 500m cells covering the 3km × 3km BNG polygon at resolution 1)
import com.databricks.labs.gbx.gridx.custom.{functions => cx}
import org.apache.spark.sql.functions._
// Reads the custom_grids view for the grid struct.
// Fills the 3km x 3km BNG polygon with 500m cells at resolution 1 (36 cells).
val poly = "POLYGON((529000 179000,529000 182000,532000 182000,532000 179000,529000 179000))"
val df = spark.table("custom_grids")
val result = df.select(cx.custom_polyfill(lit(poly), col("grid"), lit(1)).alias("cells"))
result.show(truncate = false)
+---------------------------------------------+
|cells |
+---------------------------------------------+
|[72057594038644994, ..., (36 cells at res=1)]|
+---------------------------------------------+
... (36 BIGINT cell IDs — 500m cells covering the 3km × 3km BNG polygon at resolution 1)
custom_kring
LightweightHeavyweightReturn all custom grid cells within k steps of a center cell (filled neighborhood, Chebyshev distance).
Signature: gbx_custom_kring(cell, grid, k)
Parameters:
cell—BIGINTcenter cell IDgrid— custom grid descriptor returned bygbx_custom_gridk— integer ring distance (0 = center only; 1 = 3x3 neighborhood including center)
Returns:
ARRAY<BIGINT>of cell IDs within distancek(up to(2k+1)^2cells)
- SQL
- Python (light)
- Python (heavy)
- Scala
SELECT gbx_custom_kring(360287970373976640, gbx_custom_grid(0, 1000000, 0, 1000000, 2, 1000, 1000, 27700), 1) AS ring;
+-------------------------------------------+
|ring |
+-------------------------------------------+
|[360287970373976640, ..., (9 cells at k=1)]|
+-------------------------------------------+
... (9 BIGINT cell IDs — the 3×3 neighbourhood including center cell at resolution 5)
from pyspark.sql import functions as f
from databricks.labs.gbx.pygx import functions as gx
df = _get_custom_grid_df(spark)
result = df.select(
gx.custom_kring(f.col("cell"), f.col("grid"), f.lit(1)).alias("ring")
).first()
+-------------------------------------------+
|ring |
+-------------------------------------------+
|[360287970373976640, ..., (9 cells at k=1)]|
+-------------------------------------------+
... (9 BIGINT cell IDs — the 3×3 neighbourhood including center cell at resolution 5)
from pyspark.sql import functions as f
from databricks.labs.gbx.gridx.custom import functions as cx
df = spark.table("custom_grids")
result = df.select(
cx.custom_kring(f.col("cell"), f.col("grid"), f.lit(1)).alias("ring")
).first()
+-------------------------------------------+
|ring |
+-------------------------------------------+
|[360287970373976640, ..., (9 cells at k=1)]|
+-------------------------------------------+
... (9 BIGINT cell IDs — the 3×3 neighbourhood including center cell at resolution 5)
import com.databricks.labs.gbx.gridx.custom.{functions => cx}
import org.apache.spark.sql.functions._
// Reads the custom_grids view (cell = 360287970373976640 at res=5, grid struct)
// k=1 returns 9 cells: center plus 8 surrounding cells (3x3 neighbourhood)
val df = spark.table("custom_grids")
val result = df.select(cx.custom_kring(col("cell"), col("grid"), lit(1)).alias("ring"))
result.show(truncate = false)
+-------------------------------------------+
|ring |
+-------------------------------------------+
|[360287970373976640, ..., (9 cells at k=1)]|
+-------------------------------------------+
... (9 BIGINT cell IDs — the 3×3 neighbourhood including center cell at resolution 5)
Performance Tips
1. Use Appropriate Resolution
Choose resolution based on analysis needs:
- Coarse (10km) for regional analysis
- Medium (1km) for local patterns
- Fine (100m) for detailed studies
2. Leverage Aggregators
Use aggregator functions for efficient grouping:
SELECT t.chip.cellid, gbx_bng_cellunion_agg(t.chip) AS union_chip
FROM (
SELECT explode(gbx_bng_tessellate(
'POLYGON((529000 179000, 529000 182000, 532000 182000, 532000 179000, 529000 179000))', 3
)) AS chip
) t
WHERE t.chip.cellid = 'TQ3080'
GROUP BY t.chip.cellid;
# Heavyweight SQL (active tier = heavy/Scala) — STRUCT<cellid, core, chip>:
+------+--------------------+
|cellid|union_chip |
+------+--------------------+
|TQ3080|{TQ3080, true, null}|
+------+--------------------+
... (core cell TQ3080: chip=null means the full cell polygon)
# Lightweight SQL (active tier = pygx) — BINARY (dissolved chip WKB in EPSG:27700):
+------+----------+
|cellid|union_chip|
+------+----------+
|TQ3080|[binary] |
+------+----------+
... (core cell TQ3080: [binary] is the WKB of the full TQ3080 polygon)
3. Use Generators for Expansion
Generator functions (e.g. bng_kringexplode, bng_kloopexplode) are more efficient than using explode on array results. See the generator examples above.
Next Steps
- Raster Function Reference
- VectorX Function Reference
- PMTiles Function Reference — Aggregator (
gbx_pmtiles_agg) for publishing tile pyramids