The Map widget displays an object set or object data as a configurable, interactive, geospatial visualization.
These map visualizations are comprised of two types of layers:
The Map widget supports map rendering with MapboxGL ↗. If WebGL is not supported in a user’s browser, the Map widget will render with Leaflet ↗.
The Map widget uses Mapbox as the primary source for its base map imagery, and supports an "Internal" style (custom source for base map imagery) for secure networks that cannot proxy Mapbox. To learn more about web map technology, see the Mapbox documentation ↗.
The below screenshot shows an example of configured Map widgets displaying various layer types:
In the Map widget, overlay layers represent data as points or shapes on top of a map’s base layer. The Map widget contains the following types of overlay layers:
Point layers use points or markers to represent individual objects on a map, plotted by a geohash property (stored in the form of latitude-longitude pairs). The color, icon type, and size of the points can be styled based on properties of the objects being plotted.
For configuration information, see the configure point layers section below.
Example: A map showing hospital locations as points, colored by the number of available hospital beds.
Cluster layers are ideal for larger object sets based on a geohash location property. Clusters are similar to points, except instead of plotting a single marker per object, the objects being plotted are aggregated based on their geographic proximity into clusters, with the size and/or color of the cluster configurable to represent the number of objects within a given area (or some other aggregation function such as the sum or average of a property across the objects within a region).
For configuration information, see the configure cluster layers section below.
Example: A map showing the general geographic distribution of weather stations across the country.
The Map widget’s choropleth layers display regions (such as countries or provinces) that are colored based on some attribute of, or aggregation over, the object(s) represented by that region. This provides a way to visualize variation or patterns across different regions, with the option of seeing how these values change over time.
For configuration information, see the configure choropleth layers section below.
To support custom aggregations of H3 hexagons in Functions, choropleth layers can also be used to map H3 hexagons as individual regions. See the configure choropleth layers for H3 section below.
Example: A map of states, with each state colored by its population density.
Line segment layers plot individual objects as a line segment connecting two points.
For configuration information, see the configure line segment layers section below.
Example: A map showing flight routes where the origin airport is connected to the destination airport via a line representing the flight routes.
Static layers display information that cannot be filtered dynamically and comes from a source other than object data. These layers are often most useful in providing background information to contextualize other data layers on the same map. The data for the layer can be provided in GeoJSON ↗ format or through Vector layers.
For configuration information, see the configure static layers section below.
Example: A layer showing the risk of adverse weather events occurring in various areas.
Saved layers display a map layer that was configured in the Map Layer Editor and saved as an individual resource. These layers can be shared across multiple applications, and are often used to provide background information in a consistent manner across Foundry.
Here is an image of a newly added and not yet configured Map widget alongside its configuration panel.
For the Map widget, the core configuration options are as follows:
Yes
. For more information, see the configure drawing controls section below.Yes
. For more information, see the configure time stepper controls below.For the Point layer, the main configuration options are as follows:
prominent
, specific
, or none
).For the Cluster layer, the main configuration options are as follows:
%
as the value formatter. The value specified should be a d3-format string ↗.For the Choropleth layer, the main configuration options are as follows:
choropleth boundary source
are the details for the three supported sources: Mapbox, GeoJSON, and Vector.choropleth boundary source
are the details for the three supported sources: Mapbox, GeoJSON, and Vector.prominent
, specific
, or none
).Choropleth Boundary Source: To configure a choropleth layer, you must specify the source for the boundaries that will define the regions that are shown. There are several possible sources for boundary data:
geoshape
or string
).To configure choropleth layers for H3 to support custom aggregations to display on the map widget, you will need to configure an object type, e.g. "H3 Hexagon" in Ontology Manager where each object is an H3 hexagon at the desired resolution with properties to uniquely identify each hexagon and its associated GeoJSON shape. An example of the properties for the object type is provided below:
hex_index
: a unique identifier for each H3 hexagon. Example value: 82f25ffffffffff
hex_geojson
: GeoJSON geometry of the H3 hexagon. Example value: {"type":"Polygon","coordinates":[[[-114.88722592804382,-74.86647343694071],[-110.43933775312789,-76.04791578897344],[-103.98485051466383,-75.45226049628374],[-103.08914246618076,-73.75952697882984],[-107.50751324842204,-72.74554847287561],[-112.95182804024837,-73.26746640072781],[-114.88722592804382,-74.86647343694071]]]}
The configuration options for the map widget can then be applied as follows:
hex_index
)hex_geojson
You can then configure a Function-backed property using the Non-aggregated value configuration option to aggregate Object Sets inputs by H3 hexagons and display the values in the map widget. For example, the function below would compute the derived COVID test positivity rate per H3 hexagon in the input object set:
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
import { Function, Double, FunctionsMap} from "@foundry/functions-api"; import { Objects, ObjectSet, CovidPositive, CovidTest, H3Hexagon} from "@foundry/ontology-api"; export class MyFunctions { @Function() public async calculateCovidPositivityRate(hexes: ObjectSet<H3Hexagon>, positives: ObjectSet<CovidPositive>, tests: ObjectSet<CovidTest>): Promise<FunctionsMap<H3Hexagon, Double>> { const map = new FunctionsMap<H3Hexagon, Double>(); // Set max buckets to 6000 to allow aggregations for all H3 hexagons and resolution 2 const max_buckets = {maxBuckets: 6000} const positives_bucketed = await positives .groupBy(positive => positive.hex_index.exactValues(max_buckets)) .count(); // Convert the results to a map to make the lookup more efficient than a bucketed array const positives_hex_map = new Map(); positives_bucketed.buckets.forEach((bucket: any) => { positives_hex_map.set(bucket.key, bucket.value); }); const tests_bucketed = await tests .groupBy(test => test.hex_index.exactValues(max_buckets)) .count(); const tests_hex_map = new Map(); tests_bucketed.buckets.forEach(bucket => { tests_hex_map.set(bucket.key, bucket.value); }); hexes.all().forEach(hex => { const positive_count = positives_hex_map.get(hex.hex_index); const test_count = tests_hex_map.get(hex.hex_index); if ((positive_count !== undefined) && (test_count !== undefined)) { map.set(hex, positive_count/test_count * 100); } }); return map; } }
Note that if you are using H3 hexagon resolution 2, you will need to increase the Number of Search Result Pages to 6 if you want to plot all 5,882 hexagons.
For the Line layer, the main configuration options are as follows:
line layer source
are the details for the two supported sources for aggregated line layers: GeoJSON and Vector.line layer source
are the details for the three supported sources: Point-to-Point, GeoJSON, and Vector.prominent
, specific
, or none
).Line Layer Source: Below are the different methods of loading source information to specify how lines are drawn on a line layer:
geoshape
or string
).For static layers, the main configuration options are as follows:
prominent
, specific
, or none
).Aggregated value series can be configured in three ways: simple aggregation, function aggregation, and derived aggregation.
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@Function() public costToVolume(expenses: ObjectSet<Expense>): FunctionsMap<string, Double> { const map = new FunctionsMap<string, Double>(); const costsPerCountry = expenses .groupBy(expense => expense.countryId.topValues()) .sum(expense => expense.cost); const volumePerCountry = expenses .groupBy(expense => expense.countryId.topValues()) .sum(expense => expense.volume); costsPerCountry.buckets.forEach(bucket => { var volume = volumePerCountry.buckets.find(b => b.key === bucket.key); map.set(bucket.key, bucket.value / volume); }); return map; }
(people under 30/ total population)
.Non-aggregated value series can be configured in three ways: static property, function-backed property, and time series property.
Copied!1 2 3 4 5 6 7 8 9
@Function() public countryPositivityRate(countries: ObjectSet<Country>): FunctionsMap<Country, Double> { const positivityRatePerCountry = new FunctionsMap<Country, Double>(); countries.all().forEach(country => { var positivityRate = country.dailyNewCases / country.dailyNewPositiveTests; positivityRatePerCountry.set(country, positivityRate); }); return positivityRatePerCountry; }
In the example below, the Country
object has a time series property COVID19 New Cases
, which stores a daily history of new COVID19 cases observed in the country. A time series transform then converts this daily case count into a time series recording the rate of change in cases. Finally, a time series summarizer feeds the Map data layer with the most recent value in this transformed time series; that is, it computes the last known rate of change in case values. The Color Configuration panel styles the map to highlight contrasts between countries in terms of this value. See Time series properties in Workshop for more information on time series transforms and summarizers, and the color configuration section below for more information on configuring color schemes.
The screenshot below shows configuration options for color configuration.
Configuration options for color configuration are as follows:
Color configuration: Color can be set in three ways:
Line border style: Style configuration for the lines shown on line layer or border style for other layer types.
Value formatter: Allows representing the value in a different format. For example, to represent the values as percentages, configure %
as value formatter. The value specified should be a d3-format string ↗.
Below are the main configuration options for selection, visibility, and events configuration:
True
disables the ability to select multiple objects at once. Each next selection will remove the previous selection.True
allows the layer to be hidden on the first map load. If the layer is part of a group, then the setting configured for the first layer will be considered.The below screenshot shows an example of a configured Map widget displaying different shapes alongside its configuration panel:
For the drawing controls, the core configuration options are the following:
#F29D49
, which is the hex code for light orange.0
to 1
, where the maximum opacity is 1
.#F29D49
, which is the hex code for light orange.#F29D49
, which is the hex code for light orange.0
to 1
, where the maximum opacity is 1
.#F29D49
, which is the hex code for light orange.The Map widget has a built-in time stepper that allows users to "step" forward and/or backward in time in order to see how the data on their map changes over time.
The time stepper works by publishing an object set filter (corresponding to the time window selected by the user) to a configured object set filter variable. This filter variable can be used to filter the object set that backs one or more layers shown on the map, in order to return only the objects relevant to that time window.
In order to leverage the time stepper, we recommended that the temporal objects used contain an object with some measurement per some unit of time. Each object should have a date or timestamp property that can be filtered on, such that filtering for a given window of time would allow you to load individual objects (or aggregate the objects in that window) to obtain the data to be displayed on the map.
The below screenshot shows an example map with time stepper configured:
The below screenshot shows configuration options for time stepper controls:
The core configuration options for the time stepper are the following:
The below screenshot shows an example configuration of a viewport filter.
A viewport filter outputs an object set filter variable; this allows filtering of the object set being mapped, based on the visible boundaries of the map in the widget. For example, for a map with airport locations mapped, if a user zoomed to the United States, the viewport filter will produce a filter variable which allows filtering the object set to contain objects only for US airports.
For a choropleth layer to use view port filtering, the object type being mapped needs to have a geohash property; this could be the centroid of the region.