Styling Weather Data
The benefit of MapsGL over raster-based image tile offerings is that everything is rendered at runtime, meaning you have complete control over the styling of your weather layers. When adding weather layers to your map via the map controller using addWeatherLayer
, you can customize the layer's configuration, including paint styles, to override any default styling configurations.
There are essentially two approaches to styling weather layers: basic and advanced.
Basic Style Overrides
Overriding basic paint style properties of weather layers are the most straightfoward and can result in a unique variety of weather visualizations. These include style properties like fill and stroke color, sample color scales, opacity, and more.
Sample Fill
Sample fill renderers are configured with a color scale and interval, where you provide ColorStop
values to define the color stop positions and color values. The underlying data from the source is then colorized based on the color scale when rendering data to the map. Sample fill weather layers include most encoded raster datasets, such as temperature, wind speed, dew point, precipitation, etc. All weather layers (opens in a new tab) whose type is sample
uses this render style and can be customized.
For instance, you want to render temperatures with a custom color scale at a lower data quality and using a different interval, such as every 2 degrees F instead of the default of 0.1 degree F. You would just need to provide the necessary configuration overrides for the data and sample
(opens in a new tab) paint style options for your needs:
do {
try controller.addWeatherLayer(config: {
// Custom color scale where stop values are temperatures in degrees Celsius
let colorScale = ColorScaleSpecification(stops: [
ColorStop(-67.78, .fromString("#e9c5f7")),
ColorStop(-45.56, .fromString("#f90c86")),
ColorStop(-28.89, .fromString("#d276bf")),
ColorStop(-23.33, .fromString("#6b41a7")),
ColorStop(-17.78, .fromString("#e4e7ff")),
ColorStop(-12.22, .fromString("#464ab5")),
ColorStop(-6.67, .fromString("#3375ed")),
ColorStop(-1.11, .fromString("#03f8f6")),
ColorStop(0.00, .fromString("#6bea99")),
ColorStop(7.22, .fromString("#19a00f")),
ColorStop(15.56, .fromString("#fdff87")),
ColorStop(26.67, .fromString("#cc2001")),
ColorStop(32.22, .fromString("#901436")),
ColorStop(37.78, .fromString("#e36f7e")),
ColorStop(43.33, .fromString("#ffbcff")),
ColorStop(48.89, .fromString("#b371c6")),
ColorStop(54.44, .fromString("#8a0f5f"))
])
// Override defaults on temperature configuration
var config = WeatherService.Temperatures(service: controller.service)
config.layer.paint.sample.colorScale = colorScale
config.layer.quality = .low
return config
}())
} catch {
print("Failed to add weather layer: \(error)")
}
Note that all data values for weather layers in MapsGL are defined in Metric units, which means your sample
color scale configurations also need to use Metric units.
The above configuation will result in temperatures being rendered as below:
Notice how the color scale is smoothly interpolated between your configured color stops, producing a nice gradient of temperature information. But for this map you want a bit more differentiation between temperature values for a clearer visualization. You can override the default color scale interval of 0.1 degree F (0.0555 degree C) and use something like color stops every 2 degrees F (1.11 degrees C) instead:
do {
try controller.addWeatherLayer(config: {
// Custom color scale where stop values are temperatures in degrees Celsius
var temperatureColorScale = ColorScaleOptions(stops: [
ColorStop(-67.78, .fromString("#e9c5f7")),
ColorStop(-45.56, .fromString("#f90c86")),
ColorStop(-28.89, .fromString("#d276bf")),
ColorStop(-23.33, .fromString("#6b41a7")),
ColorStop(-17.78, .fromString("#e4e7ff")),
ColorStop(-12.22, .fromString("#464ab5")),
ColorStop(-6.67, .fromString("#3375ed")),
ColorStop(-1.11, .fromString("#03f8f6")),
ColorStop(0.00, .fromString("#6bea99")),
ColorStop(7.22, .fromString("#19a00f")),
ColorStop(15.56, .fromString("#fdff87")),
ColorStop(26.67, .fromString("#cc2001")),
ColorStop(32.22, .fromString("#901436")),
ColorStop(37.78, .fromString("#e36f7e")),
ColorStop(43.33, .fromString("#ffbcff")),
ColorStop(48.89, .fromString("#b371c6")),
ColorStop(54.44, .fromString("#8a0f5f"))
])
// Set color interval to every 1.11 degrees C (2 degrees F) instead of gradient
temperatureColorScale.interval = 1.11
// Override defaults on temperature configuration
var config = WeatherService.Temperatures(service: controller.service)
config.layer.paint.sample.colorScale = .colorScale(temperatureColorScale)
config.layer.quality = .low
return config
}())
} catch {
print("Failed to add weather layer: \(error)")
}
The above result is closer as we have more defined boundaries between temperature values. However, you want even more differentation and choose to increase the color stop interval to every 5 degrees F (2.775 degrees C) instead:
do {
try controller.addWeatherLayer(config: {
// Custom color scale where stop values are temperatures in degrees Celsius
var temperatureColorScale = ColorScaleOptions(stops: [
ColorStop(-67.78, .fromString("#e9c5f7")),
ColorStop(-45.56, .fromString("#f90c86")),
ColorStop(-28.89, .fromString("#d276bf")),
ColorStop(-23.33, .fromString("#6b41a7")),
ColorStop(-17.78, .fromString("#e4e7ff")),
ColorStop(-12.22, .fromString("#464ab5")),
ColorStop(-6.67, .fromString("#3375ed")),
ColorStop(-1.11, .fromString("#03f8f6")),
ColorStop(0.00, .fromString("#6bea99")),
ColorStop(7.22, .fromString("#19a00f")),
ColorStop(15.56, .fromString("#fdff87")),
ColorStop(26.67, .fromString("#cc2001")),
ColorStop(32.22, .fromString("#901436")),
ColorStop(37.78, .fromString("#e36f7e")),
ColorStop(43.33, .fromString("#ffbcff")),
ColorStop(48.89, .fromString("#b371c6")),
ColorStop(54.44, .fromString("#8a0f5f"))
])
// Set color interval to every 2.775 degrees C (5 degrees F) instead of gradient
temperatureColorScale.interval = 2.775
// Override defaults on temperature configuration
var config = WeatherService.Temperatures(service: controller.service)
config.layer.paint.sample.colorScale = .colorScale(temperatureColorScale)
config.layer.quality = .low
return config
}())
} catch {
print("Failed to add weather layer: \(error)")
}
You can see how simply changing the color stop interval and result in drastically different visualizations, emphasizing the underlying weather story a bit differently.
Data Level-of-Detail (LOD)
This example also made use of the DataQuality
type, which is an enumerated type that specifies the level-of-detail (LOD) you want the data to be rendered at. The MapsGL SDK supports the following DataQuality
types:
Option | Description | Default |
---|---|---|
minimal | Type: ()The lowest quality setting that will provide the least amount of detail but offers the greatest amount of smoothing. |
|
low | Type: ()Provides less data detail as normal but also smooths out the data more. This is useful for weather layers where high detail is less necessary, such as surface-pressure . |
|
normal | Type: ()The default for all encoded data layers and offers a good balance between data detail and reduced network requests. |
|
medium | Type: ()Offers slightly increased data quality than normal while still maintaining reduced network requests. |
|
high | Type: ()Provides even more data quality and may be useful for certain weather layers, such as radar or satellite, where higher detail is needed. |
|
exact | Type: ()The highest quality setting that will render data tiles 1:1 with the map's active zoom level. Note that using this setting can greatly affect rendering performance depending on the data source and layer renderer type. |
|
Using this quality property allows you to increase or reduce the data resolution that gets rendered for a particular layer. For example, on a mobile device with low bandwidth or memory availability, you may want to chose a lower data quality setting so that less data is requested (e.g. fewer map tiles). The rendered output will still be smooth but with just less detail than a higher quality setting.
The following image compares temperatures at a low quality setting on the left and a high setting on the right for the same map zoom level:

Also keep in mind that lower data quality settings will reduce the amount of data that gets request, thus lowering total network requests overall.
Advanced Style Overrides
While performing basic style overrides on weather layers provides an opportunity for uniquenss and differentiation with your weather data, perhaps you want to tell a completely different story than our default weather layers.
Sample Fill
For example, an agriculture-focused application wants to include a temperature layer on their map that is strictly focused on temperatures that may affect plants and crops like frost and freeze information (opens in a new tab). So we start with the temperatures
weather layer and provide a custom colorscale configuration for our sample fill with a color stop at each temperature value that defines the categorical temperature range (e.g. hard freeze, freeze, frost):
do {
try controller.addWeatherLayer(config: {
// Custom color scale where stop values are temperatures in degrees Celsius
var temperatureColorScale = ColorScaleOptions(stops: [
ColorStop(-62.22, .fromString("#992BFF")),
ColorStop(-2.22, .fromString("#0046FF")), // hard freeze value stop
ColorStop(0, .fromString("#73DAFC")), // freeze value stop
ColorStop(2.22, .fromString("#73DAFC")) // frost value stop
])
// Disable scale interpolation so we get hard steps between color stops
temperatureColorScale.interpolate = false
// Override defaults on temperature configuration
var config = WeatherService.Temperatures(service: controller.service)
config.layer.paint.sample.colorScale = .colorScale(temperatureColorScale)
// Only draw data 2.22 degrees C (36 F) and below
config.layer.paint.sample.drawRange = ...2.22
return config
}())
} catch {
print("Failed to add weather layer: \(error)")
}
You will notice in the above code that we start our first color stop at -80 degrees F in order to color all values below 28 degrees F our hard freeze color. We are also setting a custom sample.drawRange
with a max of 36 degrees F since we don't want to render any temperature data whose value is greater than that max since we only care about freezing temperatures. We can omit a min
value in the drawRange
since we still want to render all data below 36 degrees F.
The color scale interpolation must also be disabled so that color values aren't interpolated between the defined color stops and we want clear divisions between the three temperature categories. For this, we have set interpolate
to false
on the ColorScaleOptions
.
The above configuration will produce the following result:
The data quality could also be reduced to give a less-detailed visualization and more of a general outlook:
do {
try controller.addWeatherLayer(config: {
// Custom color scale where stop values are temperatures in degrees Celsius
var temperatureColorScale = ColorScaleOptions(stops: [
ColorStop(-62.22, .fromString("#992BFF")),
ColorStop(-2.22, .fromString("#0046FF")), // hard freeze value stop
ColorStop(0, .fromString("#73DAFC")), // freeze value stop
ColorStop(2.22, .fromString("#73DAFC")) // frost value stop
])
// Disable scale interpolation so we get hard steps between color stops
temperatureColorScale.interpolate = false
// Override defaults on temperature configuration
var config = WeatherService.Temperatures(service: controller.service)
config.layer.paint.sample.colorScale = .colorScale(temperatureColorScale)
// Only draw data 2.22 degrees C (36 F) and below
config.layer.paint.sample.drawRange = ...2.22
// Set data quality to low for less detail
config.layer.quality = .low
return config
}())
} catch {
print("Failed to add weather layer: \(error)")
}