Table of Contents
• OWS Configuration - Layer Styles – Styling Section
* styles and default_style – Style Definitions * Style Types * Inheritance · Common Elements · Name
· Name, Title and Abstract · Bit-flag Masks (pq_masks) · Mask Sections · Legend · show_legend · url · multi_date
4.7.1 Styling Section
The “styling” sub-section of alayer configuration sectioncontains definitions of the various styles that layer supports. Styles officially only apply to WMS and WMTS requests. Datacube-OWS WCS GetCoverage requests will accept a styles parameter, but this is not compliant with the standard. (I.e. an unofficial extension to the WCS standard). Consequently, the “styling” section is always required, even if WMS and WMTS services are deactivated.
The “styling” section has two entries: styles and default_style.
styles and default_style
The “styles” list must be supplied, and must contain at least one style definition. There are several different types of style, each with a slightly different syntax, these are discussed below.
The “default_style” entry is optional and identifies the style that will be used by default if no style is specified in the request. If not supplied, it defaults to the first style definition in the “styles” list.
E.g. Here the second style “another_style” is the default. If the “default_style” entry were removed from this snippet, then the first style “a_style” would be the default.
"styling": { "default_style": "another_style", "styles": [ { "name": "a_style", ... }, { "name": "another_style", ... }, ] }
4.7.2 Style Definitions
Style Types
There are four distinct possible types of style. 1. Component Styles
Each component channel of the image (red, green, blue and optionally alpha) is calculated independently from the data for that pixel.
2. Colour Map Styles
Each pixel is mapped to one particular colour from a fixed pallet by applying a logical decision tree to the date for that pixel.
3. Colour Ramp Styles
A single continuous index value is calculated from the data for each pixel, and that index value mapped to a graduated colour ramp for display.
4. Hybrid Styles
A linear combination of a component style and a colour ramp style.
This can allow for a more easily visually interpreted image, but there are usually better ways to achieve the same effect on the client side.
Each style type has its own specific config entries as described in the pages linked above.
Inheritance
Styles may beinheritedfrom previously defined styles.
To lookup a style by name use the “style” and “layer” element in the inherits section. (The layer section is optional and defaults to the layer of the new style:
new_style = { "inherits": { "layer": "layer1", "style": "old_style" }, "name": "new_style", "title": "New Style", ... # Other overrides. }
Note that a style can only inherit by name from a parent style that has already been parsed by the config parser - i.e. it must appear earlier in the layer hierarchy. This restriction can be avoided using direct inheritance.
Common Elements
The following configuration elements are common to all style types.
Name
It is always required and must be unique within the layer. E.g.:
"styles": [
{"name": "a_style", ...}, # Good.
{"name": "My Style", ...}, # Poor. (Legal, but the space will need to # be escaped in URLs.
{"name": "a_style", ...}, # Error - not unique in layer. {"name": "my_style_which_is_mine_and_nobody_elses", ...},
# Poor. (Legal, but not concise) ]
Name, Title and Abstract
The “name” is a symbolic name for the style, for use in request URLs and internally. The “title” entry provides a short human-readable title for the style.
The “abstract” entry provides a longer human-readable description of the style. All three are always required and must be unique within the layer.
E.g.:
"styles": [ {
"name": "simple_rgb", "title": "Simple RGB",
"abstract": "Simple true-colour image, using the red, green and blue bands", ...
}, {
"name": "ndvi",
"title": "NDVI (red, nir)",
"abstract": "Normalised Difference Vegetation Index - a derived index that ˓→correlates well with the existence of vegetation",
... }, ]
Bit-flag Masks (pq_masks)
The “pq_masks” section allows a style to mask the output image by the bit flags in any of the flag bands defined in the
Flag Processing Sectionfor the layer.
The pq_masks section is a list of mask sections, which are AND’d together. i.e. A pixel remains visible if it matches all of the rules in the list.
Mask Sections
Each mask section contains a “band” identifier and either “flags” dictionary, or a “enum” value. A mask section may also optionally include an “invert” flag, which is False by default.
The “band” identifier refers to one of the flag-band identifiers defined in theFlag Processing Sectionfor the layer. Backwards compatibility note: The “band” identifier may be omitted if there is only one band identifier defined for the layer. However this usage is deprecated and will be removed in a future release.
Each mask must have either a “flags” entry or an “enum” entry (but not both).
If an enum entry is supplied, it should be a single integer value. A pixel is displayed if the value of the flag band for that pixel is exactly equal to the supplied integer value.
If a flags entry is supplied, it should be a dictionary is passed directly to datacube.utils.masking. make_mask. The keys of the dictionary are the flag names, and the values are the flag values - refer to the ODC product metadata for possible values. The entries of the dictionary represent bitflag comparisons that are ORed to- gether. Pixels that match ALL of the bitflags match the rule, and remain visible (unless made invisible by another rule). i.e. A pixel is DISPLAYED if the bitflags for the pixel match ALL of the entries specified in the “flags” dictionary. (and it matches all the other rules.)
If the “invert” flag is True, then the output of the masking operation is inverted (logically NOTed). i.e. only pixels that DO NOT match the uninverted rule match the inverted rule.
E.g.
# Remove pixels "pq_masks": [
# A pixel is displayed if it matches all of the rules below. #
# i.e. A pixel is masked out if it is masked out by any of the rules below. {
# This rule matches pixels that are:
# 1. Not Cloud.
# AND 2. Not Cloud Shadow
# (According to the "pixelquality" band.) #
# i.e. mask out pixels with cloud and/or cloud shadow. # "band": "pixelquality" "flags": { "cloud": "no_cloud", "cloud_shadow": "no_cloud_shadow" } }, {
# This rule matches pixels that are not water (according to the "pixelquality ˓→" band).
#
# i.e. mask out pixels that are land. #
"band": "pixelquality",
"invert": True, # Without invert, rule would match pixels ARE water. "flags": {
"water": "water" }
}, {
# This rule matches pixels with a non-zero "valid" band value. #
# i.e. mask out pixels with zero validity. #
"band": "valid",
"invert": True, # Without invert, rule would match pixels with valid band ˓→equal to zero.
"enum": 0, }
# A pixel must match all of the rules above to be displayed.
(continued from previous page)
# (i.e. A pixel masked out by ANY of the above rules will be masked out.) #
# So in this example, pixels are masked out if the are cloud, or cloud shadow, or ˓→water,
# or invalid - all other pixels are displayed. ],
Legend
Describes the legend for the style. Many options only apply for some of the styles types and are discussed below with the relevant style type.
The following legend options are supported for all styles:
show_legend
If True, a legend url is returned for this style. If False, no legend url is returned for the style. Optional - defaults to True if a the style type supports auto-legend generation, false otherwise.
If false no other legend configuration entries have any effect.
url
An external url pointing to an image file containing the legend. This url will not be exposed directly to users, the image file will be proxied behind an internal url.
A url is required if show_legend is True and the style type does NOT support auto-legend generation. If the style type DOES support auto-legend generation, setting a url deactivates legend generation. E.g.: "legend": { "show_legend": True, "url": "https://somedomain.com/path/to/legend_image.png", } multi_date
The WMS and WMTS specs allow queries over multiple date values. Datacube OWS will generally reject such queries as it is generally not clear what such a query means in the context of raster satellite data.
Datacube OWS does allow the user to define custom extensions for individual styles to define the behaviour of multi- date requests. For example, selecting two dates within a particular style might return a representation of the difference between the data for those two dates.
Multi-date behaviour is configured using the multi_date entry which is a list of multi-date handlers. multi_date‘ is optional and defaults to an empty list (no multi-date handlers, single date requests supported only).
The format of a multi-date handler varies depending on the style type but a multi-date handler must always contain a allowed_count_range entry which specifies the values for which the handler applies. The allowed_count_rangeis a tuple of two integers corresponding the minimum and maximum number of dates
accepted by that handler. The allowed count ranges of declared multi-date handlers cannot overlap and a multi-date handler cannot handle a request with 1 (or 0) dates.
E.g.
"multi_date": [ {
# This multi-date handler handles requests with 2 dates. "allowed_count_range": [2, 2],
... }, {
# This multi-date handler handles requests with between 3 and 5 dates. "allowed_count_range": [3, 5],
... }, {
# ERROR: 1 is not allowed, and 2 is already handled. "allowed_count_range": [1, 2],
... } ],
Currently multi_date is only supported forColour Ramp styles, but will likely be extended to other style types in future.
4.8 OWS Configuration - Components
Table of Contents
• OWS Configuration - Components – Component Styles
* components
· Linear Combination Components · Component scale_range
· Linear Combination Examples · Band Names That Are Reserved Words · Callback Function Components * additional_bands
* Style scale_range
4.8.1 Component Styles
Component Styles arestyleswhere each component channel of the image (red, green, blue and optionally alpha) is calculated independently from the data for that pixel.
There are three additional settings specific to component styles: scale_range <#style-scale-range>, components <#components>and additional_bands.
Component styles do NOT support automatic legend generation. If you want a legend you must provide an external
urlto a pre-prepared image.
components
The components section contains one component definition per component channel of the output image: * "red" (required)
* "green" (required) * "blue" (required) * "alpha" (optional)
Alpha is the opacity of each pixel. When alpha is 0 the image pixel is fully transparent, when 255 fully opaque. If not provided, the alpha channel is assumed to be always fully opaque (unless otherwise masked, e.g. by theextent mask
orstyle masking).
Calculating the value for each pixel has two steps: 1. Calculate an unscaled channel value.
Each component definition defines either alinear combination of raw channel dataor acallback function(as discussed in detail below) to determine the unscaled value for that channel for each pixel.
2. Scale the unscaled value to unsigned 8-bit value (0-255).
This is defined by thescale_rangeentry for the channel if it exists, or the style-widescale_range.
Linear Combination Components
In a linear combination component, every entry (apart fromscale_range) maps a band name or alias from theband dictionaryto a floating point multiplier. The pixel data values from these bands are then multiplied by these multipliers and summed to produce the unscaled channel value.
The unscaled channel value is then scaled to the to an unsigned 8-bit value (0-255) according to thescale_rangeentry for the channel if it exists, or the style-widescale_range.
Component scale_range
Defines the raw band value range that will be compressed to an 8 bit range for the output image. Band values outside this range are clipped to 0 or 255.
The component scale_range is optional and if not present defaults to thestyle-side scale_range. E.g.:
# raw values less than 15 are clipped to 0 and raw values greater than 3100 # are clipped to 255. Raw values from 15 to 3100 are linearly scaled to the # 8 bit range 0 to 255.
"scale_range": [15, 3100],
Linear Combination Examples
# Example 1. Data is a single band called "data" with # most pixel values falling between 50 and 3000. # (Uses a style-wide scale_range).
"components": { "red": { "data": 1.0 }, "green": { "data": 1.0 }, "blue": { "data": 1.0 }, }, "scale_range": (50, 3000),
# Example 2. Real colour representation of red, green and blue # channels. Separate scale_ranges defined per channel.
"components": { "red": { "red": 1.0, "scale_range": (20, 2800) }, "green": { "green": 1.0, "scale_range": (30, 3000) }, "blue": { "blue": 1.0, "scale_range": (25, 2450) }, },
# Example 3. False colour image combining red, green, blue, and # near and shortwave infrared bands
"components": { "red": {
# red channel comprises 30% swir2 band, 30% swir1 and 40% nir # Uses a component scale range
"swir2": 0.3, "swir1": 0.3, "nir": 0.4, "scale_range": (50, 3400) }, "green": {
# green channel comprises 20% nir, 40% red and 40% green bands # Uses the default style-wide scale_range.
"nir": 0.2, "red": 0.4, "green": 0.4, },
"blue": {
# green channel comprises 20% green, 80% blue bands
(continued from previous page)
# Uses the default style-wide scale_range. "green": 0.2,
"blue": 0.8, },
},
# The default style-wide scale_range, used by the green and blue # channels in this example.
"scale_range": (30, 3000)
# Example 4: Alpha channel.
# Data consists of a bands: "population_density", "vegetation" and # "urban". This style displays pure vegetation as green, and urban
# land as red with combinations as various shades of yellow (green + red). # In addition, the style will have opacity according to population
# density, so that densely populated pixels are opaque and sparsely # populated pixels are more transparent.
"channels": { "red": { "urban": 1.0, "scale_range": (0, 500), }, "green": { "vegetation": 1.0, "scale_range": (0, 500), }, "blue": {
# Blue channel not used - always zero. }, "alpha": { "population_density": 1.0, "scale_range": (4, 500) } }
Band Names That Are Reserved Words
If you are unfortunate enough to have raw data with a band named “scale_range” (or “function” which would cause the component to be treated as acallback function component), you can still access it here by defining an alias for the band in theband dictionary.
E.g.: "bands": { "red": [], "scale_range": ["scale_rng"], "function": ["func"] } ... "components": { "red": { "red": 1.0 }, "green": {
# Cannot use "scale_range" to refer to band, so # use alias.
(continues on next page)
(continued from previous page)
"scale_rng": 1.0
},
"blue": {
# Cannot use "function" to refer to band, so # use alias.
"func": 1.0
}, }
Callback Function Components
In a callback function component, the user declares a callback function using OWS’sfunction configuration format. The function must take an xarray Dataset containing the raw band data and return a xarray DataArray containing the channel data. It is the responsibility to scale it’s output to the range 0-255.
The bands needed for callback function components cannot always be determined directly from the component def- inition, so if any component in the style is a callback function component, you should ensure all needed bands are retrieved by using the additional_bands config item if necessary.
E.g.:
"components": { "red": {
# Red channel is red/blue normalised difference (Ferric Iron index) "function": "datacube_ows.band_utils.norm_diff", "pass_product_cfg": True, "kwargs": { "band1": "red", "band2": "blue", "scale_from": [-0.1, 1.0], } }, "green": {
# Green channel is nir/swir1 normalised difference (Bare Soil index) "function": "datacube_ows.band_utils.norm_diff", "pass_product_cfg": True, "kwargs": { "band1": "nir", "band2": "swir1", "scale_from": [-0.1, 1.0], } }, "blue": {
# Blue channel is swir1/swir2 normalised difference (Clay/Mica index) "function": "datacube_ows.band_utils.norm_diff", "pass_product_cfg": True, "kwargs": { "band1": "swir1", "band2": "swir2", "scale_from": [-0.1, 1.0], } },
"additional_bands": [ "red", "blue", "nir", "swir1", "swir2" ] },
additional_bands
The bands needed for a linear combination component can be trivially determined from the component definition. This is not the case for callback function components, so if any component in the style is a callback function component, (and if any bands needed by the callback function component(s) are not already being used by any lineat combination components), then these additional required bands must be declared with the additional_bands list.
The additional_bands should be a list of band names or aliases from theband dictionary. It is optional (defaults to an empty list). It is safe (but not necessary) to declare bands in additional_bands that are used directly by a linear combination component in the style.
E.g.:
"components": { "red": {
# Red channel is red/blue normalised difference (Ferric Iron index) "function": "datacube_ows.band_utils.norm_diff", "pass_product_cfg": True, "kwargs": { "band1": "red", "band2": "blue", "scale_from": [-0.1, 1.0], } }, "green": { "green": 1.0 }, "blue": { "blue": 1.0 }, }, "additional_bands": [
# The "Red" band must be declared in the additional bands or the # the Ferric Iron Index will not be able to be calculated. "red",
# The "Blue" band is already used by the linear combination # for the blue channel, so it could be left out, but it is # safe to include.
"blue" ]
Style scale_range
Defines the raw band value range that will be compressed to an 8 bit range for the output image. Band values outside this range are clipped to 0 or 255.
The style-level scale_range applies to all linear combination component channels that do not set their own component- level scale_range.
The style-level scale_range is required unless all component channels satisfy the exceptions above. See thecomponent scale_rangesection for examples.
4.9 OWS Configuration - Colour-Ramp Styles
Table of Contents
• OWS Configuration - Colour-Ramp Styles – Colour-Ramp Styles
* Calculating the Index Value · index_function
· needed_bands list * Colour Ramps
· Ramp Scale (Range) · mpl_ramp
· Manual color_ramp · Colour Point Definitions * Legend Configuration
· Legend Title · Legend Range · Legend Ticks
· Regularly spaced ticks, by size (ticks_every) · Regularly spaced ticks, by count (tick_count) · Explicit ticks (ticks)
· Tick Labels · decimal_places · Prefixes and suffixes
· Over-riding labels for individual ticks · Values passed to MatPlotLib
· Image Size · strip_location · MatPlotLib rc params * Multi-Date Requests
· aggregator_function · Multi-Date Colour Ramps · Multi-Date Legend · feature_info_label
4.9.1 Colour-Ramp Styles
Colour-ramp Styles arestyleswhere a single continuous index value is calculated from the raw data for each pixel, and that index value is mapped to a graduated colour ramp for display.
Colour-ramp styles support theelements common to all styles.
Colour-ramp styles support automatic legend generation. Specialised legend configuration is describedbelow. Note on spelling: I am Australian and spell it “colour”. Most software packages use the US spelling “color”. Within the configuration file format we use the software conventional spelling, but within the text of this documentation, I use the UK/Australian spelling.
Calculating the Index Value
Theindex_functionentry defines how the index is calculated at each pixel. The bands needed for the calculation must be declared in theneeded_bands listentry.
index_function
The index_function allows the user to declare a callback function to calculate the index value using OWS’sfunction configuration format. The function is expected to take an xarray Dataset containing all the bands in theneeded_bands list(plus any additional arguments handled by thefunction configuration format); and returns an xarray Dataset con- taining the index value.
Asmall libraryof general purpose band math functions are provided in datacube_ows.band_utils.
needed_bands list
The needed_bands entry must list the names (or aliases) of all the bands required by theindex_function. E.g.:
# Simple nir/red NDVI "index_function": { "function": "datacube_ows.band_utils.norm_diff", "pass_product_cfg": True, "kwargs": { "band1": "nir", "band2": "red" } },
"needed_bands": [ "red", "nir" ]
Colour Ramps
There are three ways to define the colour map:
1. Use the default colour ramp (A fairly garish rainbow ramp running from dark purple through blue, green, yellow, orange to dark red.)
To use the default colour ramp, just use therangestyle config entry. 2. Use a pre-defined MatPlotLib colour ramp.
To use a MatPlotLib colouor ramp, use thempl_rampandrangestyle config entries.