Skip to main content

Vector

VizX Overview · Multi-Layer Compositor · PMTiles Viewers

Interactive Maps

For multi-layer interactive maps, see the Multi-Layer Compositor.

plot_interactive renders one or more layers as a pan/zoom MapLibre GL map — the interactive counterpart to plot_static, sharing the same layer model. It is the recommended way to get an interactive map from GeoBrix results: it is scale-safe and Databricks-safe, neither of which a bare GeoDataFrame.explore() is.

  • Scale-safe. The whole map is assembled into one self-contained HTML string and embedded inline, so its size is bounded by an embed budget (max_embed_mb), not by a tile server. When the layers exceed the budget, plot_interactive degrades gracefully — by default (fallback=True) it falls back to plot_static; the Multi-Layer Compositor documents the full delivery ladder (inline embed, URL streaming, downzoom, static). Pass dry_run=True to inspect the size audit without rendering.
  • Databricks-safe. It renders via displayHTML internally and returns None. Returning a folium map (or calling .explore()) does not auto-render in a Databricks notebook; plot_interactive does the right thing in both Databricks and plain Jupyter (outside a notebook — e.g. in tests — it returns the HTML string so callers can assert on it).

plot_interactive

plot_interactive(
layers, *, basemap="carto-positron", simplify_tiles_spec=None,
max_embed_mb=None, set_cell_max_output=True, fallback=True,
center=None, zoom=None, dry_run=False, debug_mode=1, emphasis="blend",
)

layers is a Layer, a list of layers, or any bare input as_layers accepts (a geopandas.GeoDataFrame or Spark DataFrame → vector_layer, a .pmtiles archive → pmtiles_layer, a raster path / numpy.ndarrayraster_layer). Build layers with the constructors documented in the Multi-Layer Compositorvector_layer, grid_layer, raster_layer, pmtiles_layer — each of which carries its own column / grid_system / cmap / styling. The map renders as the function's last statement: in Databricks via displayHTML (returns None), outside a notebook by returning the HTML string.

Parameters:

ParameterTypeDefaultDescription
layersLayer, list[Layer], or bare inputThe layer(s) to render. A bare GeoDataFrame / Spark DataFrame / .pmtiles archive / raster is coerced via as_layers.
basemapstr"carto-positron"Base layer style: "carto-positron" (CARTO Positron) or "none" (blank dark canvas).
simplify_tiles_specdict or NoneNoneOptional vector-tile simplification spec (see the compositor page).
max_embed_mbfloat or NoneNoneMax assembled-HTML embed size, in MiB, measured against the base64-rendered HTML. None resolves to ~6 MB when set_cell_max_output is on (sized for the raised 20 MB cap), else ~3 MB.
set_cell_max_outputboolTrueOn Databricks Serverless, raise the cell-output cap to its 20 MB max before an interactive embed so a larger map isn't truncated (graceful no-op elsewhere). False leaves the cap untouched.
fallbackboolTrueWhen the embed budget is exceeded, degrade to plot_static (True) or raise (False).
center[lon, lat] or NoneNoneMap centre override.
zoomfloat or NoneNoneInitial zoom level override.
dry_runboolFalseReturn the size-audit dict (see audit_layers) without rendering — no displayHTML, no HTML string.
debug_modeint1[vizx] status verbosity: 0 silent / 1 (default) concise (audit verdict, cap-raise) / 2 adds per-layer diagnostics.
emphasisstr"blend""data" styles data layers to pop against the full-strength basemap; "blend" (default) is a softer composite. Explicit per-layer style kwargs always override.
from databricks.labs.gbx.vizx import grid_layer, plot_interactive

# Interactive H3 choropleth straight from a Spark DataFrame of cell ids —
# grid_layer decodes the cells and colours them by `band_level` through `cmap`.
plot_interactive(grid_layer(cells_df, grid_system="h3", column="band_level"))

For a multi-layer overlay (say a raster DEM under vector boundaries under grid cells), pass a list of layers — see the Multi-Layer Compositor for the layer constructors, the embed-size ladder, and the audit/simplify workflow.

Static Maps

For compositing multiple layers in a single map, see the Multi-Layer Compositor — it explains the embed-size ladder, Layer types, and the audit/simplify workflow.

plot_static renders Spark- or GeoPandas-derived geometries (or H3 cells) over a basemap as a static matplotlib figure — the GitHub-renderable counterpart to GeoDataFrame.explore() (whose Leaflet/folium output renders a blank "Make this Notebook Trusted" placeholder on GitHub and the docs site).

The basemap is fetched from a web tile server (via contextily) at execution time and rasterized into the figure, so it bakes into the committed notebook output PNG — GitHub then displays it with no network. If the executing environment has no egress, the map renders without a basemap and a warning is emitted (never a hard error).

plot_static

plot_static(
data, *, column=None, geom_col=None, grid_system=None, grid_conf=None,
max_rows=10_000, sample_seed=None, srid=None, cmap="viridis", legend=True,
basemap=True, basemap_source=None, alpha=None, edgecolor=None, fill=True,
markersize=None, title=None, fig_w=10, fig_h=10, ax=None,
emphasis="blend", debug_mode=1,
)

cmap, alpha, edgecolor, and markersize left unset resolve to values derived from emphasis ("blend" default / "data"); debug_mode controls [vizx] status verbosity (0/1/2), and sample_seed selects how the max_rows cap is filled (None = first rows; an int = a reproducible sample).

data is a Spark DataFrame or a geopandas.GeoDataFrame. Returns the matplotlib Axes; pass it back via ax= to overlay layers on one map. Every layer is reprojected to Web Mercator (EPSG:3857), so a basemap=False overlay lines up with a basemap layer on the same axes. plot_static does not call pyplot.show() — in a notebook the figure auto-displays at cell end with all overlaid layers; a script can call plt.show() itself. Pass fill=False to draw geometries as outlines only (no face), so a boundary doesn't cover the layers beneath it.

Geometry columns accept the same encodings as every other gbx_st_* function — WKT, EWKT, WKB, EWKB, and native GEOMETRY / GEOGRAPHY (coerced in-Spark via st_asbinary). Set grid_system to treat the column as DGGS cell ids instead:

grid_systemBehaviour
None (default)Column is a geometry encoding (WKT/EWKT/WKB/EWKB/GEOMETRY/GEOGRAPHY).
'h3'H3 cell ids (string index or bigint) → cell-boundary polygons (lon/lat).
'quadbin'Quadbin cell ids (bigint) → tile-boundary polygons (lon/lat).
'bng'British National Grid cell ids (string, e.g. "TQ38") → cell polygons in EPSG:27700.
'custom'Custom-grid cell ids → cell polygons; requires grid_conf= (the grid spec that defines the grid). CRS comes from the grid's srid.

Cell boundaries reuse the lightweight GridX cell→geometry implementations, so they match gbx_h3_* / gbx_quadbin_aswkb / gbx_bng_aswkb / gbx_custom_cellaswkb exactly. Each grid's native CRS is honoured (BNG is metres in EPSG:27700) and reprojected to Web Mercator for the basemap. A custom grid whose srid is <= 0 has no CRS, so its basemap is skipped (with a warning); pass basemap=False.

For a custom grid, grid_conf is the grid-spec Row/dict — the same struct the custom GridX functions consume (bound_x_min/bound_x_max, bound_y_min/bound_y_max, cell_splits, root_cell_size_x/root_cell_size_y, srid):

plot_static(cells_df, grid_system="custom", grid_conf=grid_spec, column="value")
from databricks.labs.gbx.vizx import plot_static

# H3 choropleth over a basemap, then overlay the shared-canvas boundary as a
# red outline (fill=False so it doesn't cover the cells; basemap=False so it
# doesn't re-fetch tiles). Both layers reproject to 3857, so they align.
ax = plot_static(cells_df, grid_system="h3", column="count", title="Coverage")
plot_static(grid_gdf, ax=ax, fill=False, edgecolor="red", basemap=False)

basemap_source overrides the default contextily.providers.CartoDB.Positron; basemap=False skips tiles entirely (deterministic, no network).

Adapters

The vector adapters collect to the driver for interactive mapping. By default they cap the collect at max_rows=10_000 and emit a warning if the input has more rows (pass max_rows=None to collect everything — at your own risk on large frames). The returned GeoDataFrame is in EPSG:4326, ready for .plot() (matplotlib) or — for an interactive map — plot_interactive.

For interactive (pan/zoom) maps, prefer plot_interactive over a raw GeoDataFrame.explore(): it is scale-safe (bare .explore() embeds every vertex inline, so millions of vertices hang folium and render blank) and Databricks-safe (it renders via displayHTML, whereas a returned folium map does not auto-render in a Databricks notebook). Calling gdf.explore() directly still works for small in-memory frames in plain Jupyter.

as_gdf

as_gdf(df, wkt_col="wkt", *, max_rows=10_000)

Convert a Spark DataFrame with a WKT geometry column into a geopandas.GeoDataFrame. Non-geometry columns are preserved; the WKT column is replaced by the geometry:

from databricks.labs.gbx.vizx import as_gdf

gdf = as_gdf(df_with_wkt, wkt_col="wkt")
gdf.explore() # interactive folium map (needs the [vizx] extra)

cells_as_gdf

cells_as_gdf(
df, cell_col="cellid", extra_cols=(), *,
max_rows=10_000, dissolve_by=None, dissolve_engine="auto", sample_seed=None,
)

Convert a DataFrame of H3 cell ids into a GeoDataFrame of cell-boundary polygons (boundaries computed with the h3 library). Carry through attribute columns with extra_cols.

Parameters:

ParameterTypeDefaultDescription
dfDataFrameSpark DataFrame with an H3 cell-id column.
cell_colstr"cellid"Name of the column containing H3 cell ids (bigint).
extra_colstuple or list()Additional columns to carry through to the GeoDataFrame.
max_rowsint or None10_000Row cap for driver-side collects; None collects all rows. Not applied on the product-dissolve path (see dissolve_engine).
dissolve_bystr or NoneNoneWhen set, dissolve cell polygons by this column, returning one footprint polygon per distinct value. Must be in extra_cols.
dissolve_enginestr"auto"Controls how the dissolve is performed when dissolve_by is set. See the engine table below.
sample_seedint or NoneNoneNone (default) takes the first max_rows rows (first-N, not a representative sample). An int draws a reproducible random sample via DataFrame.sample at the cost of one extra count() job.

dissolve_engine values:

ValueBehaviour
"auto" (default)Attempt the Spark-side product dissolve; if the product functions are not available (local Spark, older runtime), fall back to the geopandas driver-side dissolve automatically.
"product"Product dissolve only — uses h3_boundaryaswkb, st_geomfromwkb, st_union_agg, and st_asbinary built into Databricks Runtime (DBR 11.3+ / Serverless). Raises if the functions are not available; no silent fallback.
"geopandas"Driver-side geopandas dissolve — collects up to max_rows cells, builds per-cell polygons via the h3 library, then dissolves with GeoDataFrame.dissolve. Works everywhere.

Product dissolve path (dissolve_engine="auto" or "product"): the aggregation executes as a Spark SQL expression,

st_asbinary(st_union_agg(st_geomfromwkb(h3_boundaryaswkb({cell_col}))))

grouped by dissolve_by. This pushes the geometry union into the cluster, so only one small row per group is collected to the driver. The max_rows cap does not apply on this path.

Oversize guard: on any driver-collect path (non-dissolve or dissolve_engine="geopandas") where max_rows was not supplied explicitly, if the frame count exceeds 500,000 cells a ValueError is raised before the collect. Pass max_rows=<n>, sample_seed=<int>, or dissolve_by=<col> to proceed.

Without dissolve_by, each row represents one cell (useful for per-cell tooltips in .explore()). With dissolve_by, rows are merged per group into a single union footprint — far fewer geometries for large cell sets:

from databricks.labs.gbx.vizx import cells_as_gdf

# Per-cell choropleth:
gdf = cells_as_gdf(df_cells, cell_col="cellid", extra_cols=["count"])
gdf.explore(column="count") # choropleth (needs mapclassify, bundled in [vizx])

# Dissolve to one footprint polygon per category — uses product ST on DBR,
# falls back to geopandas on local Spark (dissolve_engine="auto" by default):
gdf_dissolved = cells_as_gdf(
df_cells,
cell_col="cellid",
extra_cols=["category"],
dissolve_by="category",
)
gdf_dissolved.explore()

# Force geopandas dissolve (no product functions required):
gdf_local = cells_as_gdf(
df_cells,
extra_cols=["category"],
dissolve_by="category",
dissolve_engine="geopandas",
)

grid_as_gdf

grid_as_gdf(grid, srid=None)

Convert a grid spec — as returned by rst_h3_gridspec — into a 1-row GeoDataFrame of its bounding-box rectangle in EPSG:4326. Compose with cells_as_gdf(...).explore() to overlay the shared canvas boundary over the H3 cells it contains.

Parameters:

ParameterTypeDefaultDescription
gridRow, dictA Spark Row or dict with xmin, ymin, xmax, ymax fields — the struct that rst_h3_gridspec returns in its grid field.
sridint or NoneNoneCRS override. Falls back to the grid's own srid field; if both are absent, EPSG:4326 is assumed. When the source CRS is not 4326, the bounding box is reprojected via pyproj.

Optional metadata fields pixel_size, width, and height are carried through if present on the input.

from databricks.labs.gbx.vizx import cells_as_gdf, grid_as_gdf

# grid_row is the 'grid' field from an rst_h3_gridspec result
grid_gdf = grid_as_gdf(grid_row)
cells_gdf = cells_as_gdf(df_cells, cell_col="cellid", extra_cols=["count"])

# Compose: H3 cells as a choropleth with the canvas boundary drawn on top
m = cells_gdf.explore(column="count")
grid_gdf.explore(m=m, color="black", style_kwds={"fill": False})

See the H3 rasterize notebook for a worked example pairing grid_as_gdf with cells_as_gdf to build a shared-canvas overlay.