Layer Styling: Visualize Tab
The UDF builder displays data from the UDF into the map view. You can change the visual representation of a UDF's output is configured under the "Visualize" tab:
You'll notice a few differences to the Editor:
- The Visualise tab isn't written in Python, rather this is a JSON file
- There are a few defaults namely
TileLayer
,rasterLayer
andvectorLayer
- "Surprise Me" button. Try it out for yourself, see what happens! (you can always
Ctrl + Z
to go back if you don't like it)
You can explore this example right here for yourself. Click on the "UDF Builder" icon on the left, just below the Fused logo to open the code editor:
Basics of Visualize Tab
The Visualize tab is built on top of DeckGL, a JavaScript front-end framework build for large dataset visualizations.
Fused works with on a either a File or Tile basis (read more about this here). The styling will differ for each:
Tile
-> We're leveraging DeckGL'sTileLayer
in the Map view as a basis allowing us to render only data that is in the viewport at any given moment.File
-> All of the output data is in a single file, so theTileLayer
part is ignored and the sub-layersvectorLayer
orrasterLayer
are used directly:
We have created 2 Fused-specific sub-layers:
rasterLayer
for all raster-based visualisations (if your UDF returns a PNG for example)vectorLayer
for all vector-based visualisations (if your UDF returns aGeoDataFrame
for example)
Under the hood Fused will use whichever sublayer fits your UDF output, but keep in mind that both are defined in each UDF:
// psuedo-code overview of Visualize tab parameters
{
"tileLayer": {
"@@type": "TileLayer",
...
},
// This is a Fused-specific sublayer for all raster outputs
"rasterLayer": {
"@@type": "BitmapLayer"
...
},
// This is a Fused-specific sublayer for all vector outputs
"vectorLayer": {
"@@type": "GeoJsonLayer",
...
}
}
Depending on what your UDF returns, you can use different layer types (this is the current supported list):
- Vector
H3HexagonLayers
for UDFs returning a JSON with a column containing H3 indices - Vector
GeoJsonLayer
for UDFs returning aGeoDataFrame
(or anyDataFrame
with a geometry column) - Raster
BitmapLayer
for UDFs returning an array
Their visualization styles can be configured with DeckGL properties.
You can hold Cmd
on MacOS or Ctrl
on Windows / Linux to tilt the map view.
You can try it out in the map right below this in the "Vector H3HexagonLayer
" section 👇
Vector H3HexagonLayer
At the moment, any pd.DataFrame
will be rendered using the vectorLayer config. If your DataFrame
does have H3 indices you can use H3HexagonLayer
to display those as hexagon vectors.
In this case, the config column getHexagon
should be set with the name of the DataFrame
column of H3 indices. The rendered hexagons can be styled by setting values from a different column in getFillColor
& getElevation
.
Expand to see Visualise code
{
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 19,
"tileSize": 256,
"pickable": true
},
"vectorLayer": {
"@@type": "H3HexagonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"extruded": false,
"opacity": 1,
"coverage": 0.9,
"lineWidthMinPixels": 5,
// This assumes your UDF returns a DataFrame with a column called 'hex' containing all the H3 indices
"getHexagon": "@@=properties.hex",
"getLineColor": {
"@@function": "hasProp",
"property": "metric",
"present": "@@=[(1 - properties.metric/500) * 255, 0, 255]",
"absent": [200, 200, 200]
},
"getFillColor": {
"@@function": "hasProp",
"property": "metric",
"present": "@@=[255, (1 - properties.metric/500) * 255, 0]",
"absent": [220, 255, 100]
},
"getElevation": {
"@@function": "hasProp",
"property": "metric",
"present": "@@=properties.metric",
"absent": 1
},
"elevationScale": 10
}
}
Vector GeoJsonLayer
The visualization of the output of a UDF that returns a DataFrame
or GeoDataFrame
can be configured dynamically based on column values. Attributes of the vectorLayer
can be set to use either hardcoded values or column values, such as:
- Line color (
getLineColor
) and line width (getLineWidth
) - Elevation (
getElevation
) withextruded
set to true lineWidthUnits
helps maintain visual consistency across zoom levels when set topixels
Expand to see Visualise code
{
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 15,
"tileSize": 256,
"pickable": true
},
"vectorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"extruded": true,
"getElevation": "@@=properties.stats*1",
"lineWidthMinPixels": 1,
"getLineWidth": "@@=properties.stats*10",
"getLineColor": {
"@@function": "hasProp",
"property": "stats",
"present": "@@=[properties.stats*5, properties.stats*3, properties.stats*2]",
"absent": [255, 0, 255]
},
"getFillColor": "@@=[properties.stats*5, properties.stats*3, properties.stats*2]"
}
}
Color styling
There are 4 ways to set the color for the stroke (getLineColor
) and fill (getFillColor
) of a GeoJsonLayer
. These examples show how to set it for the fill with getFillColor
, and the same syntax applies for the stroke with getLineColor
. They all modify the visualization config for this UDF.
@fused.udf
def udf(
bbox: fused.types.Bbox = None,
table_path: str = "s3://fused-asset/infra/building_msft_us/",
):
import numpy as np
import random
utils = fused.load("https://github.com/fusedio/udfs/tree/eda5aec/public/common/").utils
# Load data
gdf=utils.table_to_tile(bbox, table=table_path)
# Assign random numbers
gdf['value'] = np.random.randint(0,10, len(gdf))
# Assign random classes
categories = ['residential', 'commercial', 'health', 'public']
gdf['class'] = [random.choice(categories) for _ in range(len(gdf))]
print(gdf)
return gdf
With a single hardcoded color
Expand to see Visualise code
{
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 19,
"tileSize": 256,
"pickable": true
},
"rasterLayer": {
"@@type": "BitmapLayer",
"pickable": true
},
"vectorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"lineWidthMinPixels": 1,
"pointRadiusMinPixels": 1,
"getFillColor": [20,200,200,100]
}
}
Based on a property value
Expand to see Visualise code
{
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 15,
"tileSize": 256,
"pickable": true
},
"rasterLayer": {
"@@type": "BitmapLayer",
"pickable": true
},
"vectorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"extruded": true,
"getElevation": "@@=properties.stats*1",
"lineWidthMinPixels": 1,
"getFillColor": "@@=[properties.value*50, properties.value*30, properties.value*2]"
}
}
Alternatively, to support a default color when a value is absent.
Expand to see Visualise code
{
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 15,
"tileSize": 256,
"pickable": true
},
"rasterLayer": {
"@@type": "BitmapLayer",
"pickable": true
},
"vectorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"extruded": true,
"getElevation": "@@=properties.stats*1",
"lineWidthMinPixels": 1,
"getFillColor": {
"@@function": "hasProp",
"property": "value",
"present": "@@=[properties.value*50, properties.value*3, properties.value*2]",
"absent": [
255,
0,
255
]
}
}
}
Using colorCategories
To set the color with colorCategories, use the attr
property to specify the table column for the values, and the colors
property to define the desired color palette.
Expand to see Visualise code
{
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 19,
"tileSize": 256,
"pickable": true
},
"rasterLayer": {
"@@type": "BitmapLayer",
"pickable": true
},
"vectorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"lineWidthMinPixels": 1,
"pointRadiusMinPixels": 1,
"getFillColor": {
"@@function": "colorCategories",
"attr": "class",
"domain": [
"residential",
"commercial",
"health",
"public"
],
"colors": "Bold"
}
}
}
Note that unexpected behaviors may arise if too many domains are used.
Using colorContinuous
To set the color with colorContinuous, use the attr
property to specify the table column for the values, and the colors
property to define the desired color palette.
Expand to see Visualise code
{
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 19,
"tileSize": 256,
"pickable": true
},
"rasterLayer": {
"@@type": "BitmapLayer",
"pickable": true
},
"vectorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"lineWidthMinPixels": 1,
"pointRadiusMinPixels": 1,
"getFillColor": {
"@@function": "colorContinuous",
"attr": "value",
"domain": [
0,
10
],
"colors": "Peach",
"nullColor": [
184,
184,
184
]
}
}
}
Raster BitmapLayer
Raster layers can be set to display a tooltip on hover by setting the pickable
property to true
. See DeckGL documentation.
Expand to see Visualise code
{
"tileLayer": {
"@@type": "TileLayer",
"minZoom": 0,
"maxZoom": 19,
"tileSize": 256,
"pickable": true
},
"rasterLayer": {
"@@type": "BitmapLayer",
"pickable": true
}
}
The transparency of raster images can be set in two ways:
- In RGB images, the color black (0,0,0) is automatically set to full transparency.
If a 4-channel array is passed, i.e. RGBA, the value of the 4th channel is the transparency.
Custom loadingLayer
and errorLayer
When tileLayer
has "@@type": "DebugTileLayer"
set loadingLayer
and errorLayer
can be configured to show the user that the UDF is still processing or that an error occurred. This is helpful for debugging.
Expand to see Visualise code
{
"tileLayer": {
"@@type": "DebugTileLayer",
"minZoom": 0,
"maxZoom": 15,
"tileSize": 256,
"pickable": true
},
"rasterLayer": {
"@@type": "BitmapLayer",
"pickable": true
},
"vectorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"extruded": true,
"getElevation": "@@=properties.stats*1",
"lineWidthMinPixels": 1,
"getLineColor": {
"@@function": "hasProp",
"property": "stats",
"present": "@@=[properties.stats*5, properties.stats*3, properties.stats*2]",
"absent": [
255,
0,
255
]
},
"getFillColor": "@@=[properties.stats*5, properties.stats*3, properties.stats*2]"
},
"loadingLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": false,
"pickable": true,
"lineWidthMinPixels": 10,
"getLineColor": [
25,
55,
0,
255
],
"getFillColor": [
5,
20,
255,
40
]
},
"errorLayer": {
"@@type": "GeoJsonLayer",
"stroked": true,
"filled": true,
"pickable": true,
"lineWidthMinPixels": 10,
"getLineColor": [
255,
255,
0,
255
],
"getFillColor": [
255,
20,
255,
40
]
}
}