Skip to main content

Fused Map

Type: fused-map

Interactive map with tile, UDF and SQL layers.

Supports children: No

Interactive map: a Mapbox basemap with every data layer (mvt, raster, geojson, h3, heatmap, arc, scatterplot, deck-geojson, fused-hex) rendered through deck.gl. Layers load data from a UDF directly (udf), from a DuckDB query (sql), from a tile endpoint (tileUrl) or from a Fused server's hex query endpoints (fused-hex with source). A sidebar lets viewers restyle, filter and re-query layers at runtime.

Example — UDF result (GeoDataFrame)

{
"type": "fused-map",
"props": {
"layers": [{
"id": "buildings",
"type": "geojson",
"udf": "{{my_udf}}",
"tooltip": true,
"style": { "fillColor": { "type": "continuous", "attr": "height", "palette": "Sunset" } }
}]
}
}

Example — UDF as H3 tiles

{
"type": "fused-map",
"props": {
"layers": [{
"id": "hexes",
"type": "h3",
"udf": "{{my_h3_udf}}",
"tile": true,
"style": { "fillColor": { "type": "continuous", "attr": "count", "domain": [0, 500] } }
}]
}
}

Example — MVT tile layer

{
"type": "fused-map",
"props": {
"layers": [{
"id": "counties",
"type": "mvt",
"tileUrl": "https://tiles.fused.io/public/my_tileset/{z}/{x}/{y}",
"style": { "fillColor": [100, 150, 200], "opacity": 0.6 }
}]
}
}

Example — SQL with lat/lng points and a filter

{
"type": "fused-map",
"props": {
"layers": [{
"id": "sites",
"type": "geojson",
"sql": "SELECT name, lat, lng, score FROM {{my_udf}}",
"filters": [{ "attr": "score", "type": "range", "min": 0.5 }],
"style": { "fillColor": [255, 80, 0], "pointRadius": 8 }
}]
}
}

Example — raster tile layer

{
"type": "fused-map",
"props": {
"layers": [{
"id": "seismic",
"type": "raster",
"tileUrl": "https://udf.ai/<token>/run/tiles/{z}/{x}/{y}?format=png",
"style": { "opacity": 0.8 }
}]
}
}

Example — ERA5 / gridMET / indexed H3 data (fused-hex)

{
"type": "fused-map",
"props": {
"layers": [{
"id": "era5-t2m",
"type": "fused-hex",
"source": {
"endpoint": "/retrieve/era5/daily/bbox",
"dateMin": "2024-07-15",
"dateMax": "2024-07-15",
"variables": ["t2m_mean"]
},
"tooltip": ["hex", "date", "t2m_mean"],
"style": { "fillColor": { "type": "continuous", "attr": "t2m_mean", "domain": [270, 310] } }
}]
}
}

Raster layers with a tileUrl fetch PNG tiles from a publicly reachable XYZ endpoint; only opacity and visible apply. udf with tile: true instead runs the UDF per tile through the workbench (or the canvas share token on a shared page), so no share token is needed and edits to the UDF re-render the layer.

Choosing a source

  • udf without tile: one whole run. Rows become features (geojson, h3, heatmap, arc, scatterplot); an image result becomes one raster picture at the bounds the run returned or was sent. Not valid for mvt — that needs tile: true with udf, or a tileUrl.
  • udf with tile: true: the UDF runs per XYZ tile; use for large or tile-shaped UDFs (raster → PNG, h3 → hexagons, geojson → vector features). Tile layers never auto-fit.
  • sql: a DuckDB query over {{udf}} results; rows become features via geometryColumn / latColumn+lngColumn / h3Column.
  • source (fused-hex only): a Fused server's ERA5, gridMET or /h3/query endpoint, queried per XYZ tile; no udf or sql.
  • Whole-run results larger than the viewer's "Max amount of data to auto-load" setting (default 50 MB) are not loaded until the viewer confirms, and UDFs marked for manual runs show a Run button instead of running on load. Prefer tile: true or a narrowing sql for big datasets.

Layer types

  • geojson: polygons, lines and points from any source. deck-geojson is an alias of geojson and renders identically — prefer geojson.
  • h3: hexagons from h3Column (auto-detected from common names like hex, h3 when omitted), styled with coverage, extruded, elevationAttr.
  • scatterplot: point circles; pointRadius in pixels (default 5), lineColor/lineWidth for the outline.
  • heatmap: density of points; weight comes from a continuous fillColor.attr (1 per point when fillColor is static), pointRadius is the kernel radius in pixels (default 30). Not pickable, no tooltip.
  • arc: one arc per row. Give the endpoints with startLatColumn/startLngColumn and endLatColumn/endLngColumn (auto-detected from common names when omitted), or a source/target property holding [lng, lat], or a LineString whose first and second vertices are the ends. fillColor colours the source end, lineColor the target end, lineWidth the arc width.
  • mvt / raster: tiled from tileUrl, or from udf with tile: true.
  • fused-hex: H3 tiles queried from a Fused server; each XYZ tile's bbox is sent to source.endpoint (a full URL, or a path on the current server; /h3/query when only source.path is set): /retrieve/era5/daily/bbox, /retrieve/era5/hourly/bbox and /retrieve/gridmet/bbox serve fixed resolution 7 datasets and need dateMin/dateMax; /h3/query reads any indexed source.path and needs the layer's h3Column set to the location's indexed space column (set source.timeColumn too so latest/first can order rows). Each hex's rows over the window are reduced to one (reduce: latest, first, mean, min, max, sum). Tiles load from zoom 7 for a single day; unless minZoom is set the floor rises with the window (about one zoom level per 4x more time steps) so a tile stays within the server's row limit, and nothing draws below it. A tile the server still rejects as too large shows an error: zoom in or narrow the window. Row cells cover their hexagon whole unless style.coverage is set (default 1, where other hex layers default to 0.9). It reads source instead of udf/sql, is never auto-detected, never auto-fits and takes no bounds. Set source.overview ({} is enough) to outline, from zoom 3 up to the floor, the H3 cells of the files the query reads (no rows are read): one request lists them, with no tiles and no values, so the outlines show where data exists, not what it holds. ERA5 retrieve endpoints and /h3/query only (for /h3/query the world extent lists the whole location); it is an error on gridMET. overview.minZoom (default 3) must sit below the floor for the overview to draw, and overview.extent limits the area it looks up and also confines the row tiles: none are requested outside it, and cells are drawn only inside it, overview and rows alike, by cell centre (default: the whole world). Overview cells are styled apart from the rows by style.overview (fused-hex only): lineColor and fillColor (default: #afafaf stroke, no fill) each take a single colour, "inherit" (the layer's own stroke/fill; when that is data-driven, no overview is drawn and a warning shows on the layer card, rows unaffected), or a data-driven {type: "continuous"|"categorical", attr, ...} colouring cells by row_count_total (rows in the whole file) or row_count_window (rows in the file sections the current date window reads) -- the only two overview attributes, since a files overview carries no other values. Also lineWidth (default 1, 0 = no stroke), opacity (the fill's, default 0.35) and coverage (default 1).

Colours

style.fillColor and style.lineColor accept an [r, g, b] or [r, g, b, a] array, a CSS colour string, or a data-driven object:

  • Continuous: { "type": "continuous", "attr": "<numeric property>", "domain": [min, max], "palette": "Sunset", "steps": 7, "reverse": false, "nullColor": "#b8b8b8" }. domain defaults to the data's min/max, palette to "Sunset". Sequential palettes (CARTOColors): Sunset, SunsetDark, Teal, TealGrn, Emrld, BluGrn, BluYl, Mint, DarkMint, Purp, PurpOr, Magenta, Burg, BurgYl, RedOr, OrYel, Peach, PinkYl, BrwnYl.
  • Categorical: { "type": "categorical", "attr": "<property>", "colors": { "<value>": "#hex" }, "palette": "Bold", "nullColor": "rgba(128,128,128,0.5)" }. Omit colors to auto-assign from the palette (default "Bold"). Qualitative palettes: Bold, Vivid, Safe, Prism.

A legend is drawn only for data-driven colours (see legend and showLegend).

Every widget is defined as { "type": "fused-map", "props": { ... } }. The properties below describe the props object.

Props

Loading ....

Raw schema

Download the full schema file: /widget-schema/fused-map.json