Filtering Data
When working with data on your map, you may want to filter the data to only show relevant information for your particular use case. There are different ways to filter data in MapsGL depending on the type of data you are working with.
Filtering Raster Data
When working with raster data, only layers associated with encoded raster data sources can be filtered.
To filter encoded raster data, simply adjust the minimum and maximum values of the layer's drawRange
property, which is an option of the sample
paint style configuration. The values you provide for drawRange
will determine the range of values that will be displayed for that layer on the map. These values must be within the range of the data source's min
and max
values and in the same units as the data source.
Filtering Raster Weather Data
Filtering raster weather data is a common use case when you want to display only a subset of the data on the map. In this case, you just need to override the default paint style's drawRange
values in the weather layer's overrides object when adding the layer to the map.
For example, if you wanted to filter the temperatures
layer to only show values between 50°F and 80°F, you would need to convert the range to degrees Celsius as that is what temperature data is stored as in the data source. The following would be the appropriate configuration for this type of filter:
const FtoC = (f) => (f - 32) * 5 / 9;
controller.addWeatherLayer('temperatures', {
paint: {
sample: {
drawRange: { min: FtoC(50), max: FtoC(80) }
}
}
});
The above code will give you a result where only temperatures between 10°C and 26.67°C are displayed on the map:
Alternatively, you can also filter the data by only specifying either a minimum or maximum value for drawRange
and the other value will be set to the data source's min
or max
value, respectively. For example, if you wanted to only show temperatures above 80°F, you just need to set the drawRange.min
value:
controller.addWeatherLayer('temperatures', {
paint: {
sample: {
drawRange: { min: FtoC(80) }
}
}
});
Similarly, you can show temperatures below 50°F by setting the drawRange.max
value:
controller.addWeatherLayer('temperatures', {
paint: {
sample: {
drawRange: { max: FtoC(50) }
}
}
});
Since filtering is supported for all layers associated with encoded raster data sources, you can apply the same filtering techniques described above to layers rendered with other styles such as the wind speed particles layer. In this case, wind speed is stored in meters per second (m/s) in the data source, so you would need to convert the drawRange
values to m/s as well:
const mphToMs = (mph) => mph * 0.44704;
controller.addWeatherLayer('wind-particles', {
paint: {
sample: {
drawRange: { min: mphToMs(20) }
}
}
});
Filtering Vector Data
Vector data, which includes data from GeoJSON or vector tile sources, can be filtered using the filter
property on a layer's configuration. The filter
option allows you to specify a set of conditions that must be met for a feature to be rendered on the map.
For pre-configured built-in weather layers, you can filter vector layers by setting the filter
property in the weather layer's overrides object.
Vector data filters are defined using a variety of operators and expressions to filter data based on properties and their values associated with a vector feature. So in order to filter vector data, you need to know the properties of the data you are working with.
For example, if you set up a data source of cities from Natural Earth (opens in a new tab) and wanted to filter the cities
layer to only show cities with a population greater than 1 million, you would need to know the name of the property that stores the population data from the GeoJSON source. Each Natural Earth feature in the cities dataset contains information about the population of the city in the POP_MAX
property:
{
"type": "Feature",
"properties": {
"SCALERANK": 1,
"LABELRANK": 1,
"FEATURECLA": "Populated place",
"NAME": "Houston",
"SOV0NAME": "United States",
"SOV_A3": "USA",
"ADM0NAME": "United States of America",
"ADM0_A3": "USA",
"ADM1NAME": "Texas",
"ISO_A2": "US",
"LATITUDE": 29.82192,
"LONGITUDE": -95.341925,
"POP_MAX": 4459000,
"POP_MIN": 3647574,
"POP_OTHER": 3607616,
"RANK_MAX": 12,
"RANK_MIN": 12
},
"geometry": {
"type": "Point",
"coordinates": [
-95.348436,
29.741273
]
}
}
You would then set up a "greater than" logical expression as your filter to only show cities with a population greater than 1 million:
controller.addLayer('cities', {
type: 'circle',
source: 'cities',
paint: {
fill: {
color: '#4E00C1'
},
circle: {
radius: 6
}
},
filter: ['>', 'POP_MAX', 1000000]
});
Logical Expressions
The following logical expressions are supported for filtering vector data, where input
is the value associated with the specified property name and value
is the value you want to compare against:
Expression | Description |
---|---|
['!', boolean] | Negates the input such that false is returned if the input is true , and true is returned if the input is false |
['==', input, value] | Returns true if the input and value are equal, otherwise false . |
['!=', input, value] | Returns true if the input and value not equal, otherwise false . |
['<', input, value] | Returns true if the input is less than the value, otherwise false . |
['<=', input, value] | Returns true if the input is less than or equal to the value, otherwise false . |
['>', input, value] | Returns true if the input is greater than the value, otherwise false . |
['>=', input, value] | Returns true if the input is greater than or equal to the value, otherwise false . |
['in', input, value1, value2, ...] | Returns true if the input matches any one of the provided values, otherwise false . |
['all', boolean, ...] | Returns true if all of the inputs are true , otherwise false . |
['any', boolean, ...] | Returns true if any of the inputs are true , otherwise false . |
Expressions offer a powerful way to filter vector data in layers so that only the information you care about is displayed on the map. You can also combine multiple expressions to create more complex filters that meet your specific needs.
For example, you have added a custom vector tile set consisting OpenStreetMap road data and you want to create a layer only showing bridges from that dataset. You can add a filter that uses the all
expression to check if a road feature's brunnel
property is equal to bridge
and the class
property is equal to one of the values motorway
, trunk
, or primary
, which are the classes of roads we're interested in:
controller.addLayer('roads', {
type: 'line',
source: 'roads',
paint: {
line: {
color: '#FF0000',
width: 2
}
},
filter: ['all',
['==', 'brunnel', 'bridge'],
['in', 'class', 'motorway', 'trunk', 'primary']
]
});
Filtering Vector Weather Data
When it comes to filtering vector weather data, you would use the same set of logical expressions as outlined above. But since you aren't configuring these layers, you would instead provide your filter conditions in the weather layer's overrides object.
For example, if you wanted to filter the stormreports
layer to only show reports of wind, you would set the filter in the overrides
object when adding the layer to the map:
controller.addWeatherLayer('stormreports', {
filter: ['==', 'report.cat', 'wind']
});
Filtering weather alerts based on category is another common use case for displaying weather data. For the alerts
layer, you can easily filter alerts based on their VTEC codes so that only certain ones are displayed. For example, you only want to show severe thunderstorm warnings:
controller.addWeatherLayer('alerts', {
filter: ['==', 'VTEC', 'SV.W']
});
You can use the in
expression to filter alerts based on multiple VTEC codes, such as a "severe" category that includes severe thunderstorm and tornado watches and warnings:
controller.addWeatherLayer('alerts', {
filter: ['in', 'VTEC', 'SV.A', 'SV.W', 'TO.A', 'TO.W']
});