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
udfwithouttile: one whole run. Rows become features (geojson, h3, heatmap, arc, scatterplot); an image result becomes onerasterpicture at the bounds the run returned or was sent. Not valid formvt— that needstile: truewithudf, or atileUrl.udfwithtile: 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-hexonly): a Fused server's ERA5, gridMET or/h3/queryendpoint, queried per XYZ tile; noudforsql.- 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: trueor a narrowingsqlfor big datasets.
Layer types
geojson: polygons, lines and points from any source.deck-geojsonis an alias ofgeojsonand renders identically — prefergeojson.h3: hexagons fromh3Column(auto-detected from common names like hex, h3 when omitted), styled withcoverage,extruded,elevationAttr.scatterplot: point circles;pointRadiusin pixels (default 5),lineColor/lineWidthfor the outline.heatmap: density of points; weight comes from a continuousfillColor.attr(1 per point when fillColor is static),pointRadiusis the kernel radius in pixels (default 30). Not pickable, no tooltip.arc: one arc per row. Give the endpoints withstartLatColumn/startLngColumnandendLatColumn/endLngColumn(auto-detected from common names when omitted), or asource/targetproperty holding [lng, lat], or a LineString whose first and second vertices are the ends.fillColorcolours the source end,lineColorthe target end,lineWidththe arc width.mvt/raster: tiled fromtileUrl, or fromudfwithtile: true.fused-hex: H3 tiles queried from a Fused server; each XYZ tile's bbox is sent tosource.endpoint(a full URL, or a path on the current server; /h3/query when onlysource.pathis set):/retrieve/era5/daily/bbox,/retrieve/era5/hourly/bboxand/retrieve/gridmet/bboxserve fixed resolution 7 datasets and needdateMin/dateMax;/h3/queryreads any indexedsource.pathand needs the layer'sh3Columnset to the location's indexed space column (setsource.timeColumntoo 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; unlessminZoomis 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 unlessstyle.coverageis set (default 1, where other hex layers default to 0.9). It readssourceinstead ofudf/sql, is never auto-detected, never auto-fits and takes nobounds. Setsource.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, andoverview.extentlimits 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 bystyle.overview(fused-hex only):lineColorandfillColor(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 byrow_count_total(rows in the whole file) orrow_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. AlsolineWidth(default 1, 0 = no stroke),opacity(the fill's, default 0.35) andcoverage(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" }.domaindefaults to the data's min/max,paletteto "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)" }. Omitcolorsto 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
Raw schema
Download the full schema file: /widget-schema/fused-map.json