======================================= OWS Configuration - Colour-Ramp Styles ======================================= .. contents:: Table of Contents Colour-Ramp Styles ------------------ Colour-ramp Styles are :doc:`styles ` where 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 the `elements common to all styles `_. Colour-ramp styles support automatic legend generation. Specialised legend configuration is described `below <#legend-configuration>`__. .. 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 --------------------------- There are two methods to specify the calculation of the index value: Expressions (simple calculations) ================================= index_expression ++++++++++++++++ The ``index_expression`` entry takes a string written in a simple expression language. Lexical units are floating point or integer constants, or band names (alias-aware). Simple operators (+, -, /, *, **) and parentheses work in the usual manner. Note that you do NOT need to explicitly specify ``needed_bands`` when using an ``index_expression``. E.g. :: # Simple nir/red NDVI "index_expression": "(nir-red)/(nir+red)", Functions (complex calculations) ================================= For more complex calculations than are supported by the expression syntax, The `index_function <#index-function>`__ entry can define how the index is calculated at each pixel using an arbitrary Python function. The bands needed for the calculation must be declared in the `needed_bands list <#needed-bands-list>`__ entry. index_function ++++++++++++++ The ``index_function`` allows the user to declare a callback function to calculate the index value using OWS's :doc:`function configuration format `. The function is expected to take an xarray Dataset containing all the bands in the `needed_bands list <#needed-bands-list>`__ (plus any additional arguments handled by the :doc:`function configuration format `); and returns an xarray Dataset containing the index value. A `small library `_ of 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 the `index_function <#index-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 the `range <#ramp-scale-range>`__ style config entry. 2. Use a pre-defined MatPlotLib colour ramp. To use a MatPlotLib colour ramp, use the `mpl_ramp <#mpl-ramp>`__ and `range <#ramp-scale-range>`__ style config entries. 3. Define your own colour ramp. To define a custom colour ramp, use the `color_ramp <#manual-color-ramp>`__ style config entry. Ramp Scale (Range) ================== For the Matplotlib colour ramps and the default colour ramp, you need to specify a value range over which the colour ramp is applied. The ``range`` element can be set to a tuple containing the index function values that should be mapped to the lowest and highest colour ramp values. Values outside the configured range are clipped to the closest extreme of the colour ramp. E.g.:: "range": [-1.0, 1.0] mpl_ramp ======== You can use any named matplotlib colour ramp, see `the matplotlib documentation `_ for details. for a list of supported ramps. Matplotlib colour ramps run from 0.0 to 1.0 to scale them to the output of your index function, define a `range <#ramp-scale-range>`__. E.g.:: "mpl_ramp": "RdBu", "range": [0.0, 1200.0] Manual color_ramp ================= A colour ramp can be created manually using the ``color_ramp`` style configuration entry. ``color_ramp`` should be a list of `colour point definitions <#colour-point-definition>`_. Each colour point definition describes a mapping from a value to a colour. The list should be sorted in order of ascending value. If the index function value for a pixel exactly matches the first colour point definition value, then that definition's colour is used. A pixel with a value less than the lowest value in the ramp will be the colour of the first colour point. A pixel with a value greater than than the highest value in the ramp will be the colour of the last colour point. Pixels with index function value in between two colour point values will have be coloured a average of the rgb values of those two colour points, weighted by the difference between the pixel index function value and the values of the two colour points. Colour Point Definition +++++++++++++++++++++++ Each Colour Point Definition must have a numeric ``value`` and a ``color`` in html hex format (e.g. ``#FFFFFF``, ``#ffffff``, ``#FFF`` and ``#fff`` all refer to pure white). A Colour Point may also optionally have an ``alpha`` entry which should be a floating point entry between 0.0 (fully transparent) and 1.0 (fully opaque). If not provided, alpha defaults to fully opaque. A Colour Point may also have an optional "legend" section which affects automatic legend generation, and is discussed below. E.g.:: # <0: transparent # 0: black # 0-1: ramping from black to red # 1-10: ramping from red to blue # >10: blue "color_ramp": [ { "value": -0.00000000001, "color": "#000", "alpha": 0.0 }, { "value": 0.0, "color": "#000", }, { "value": 1.0, "color": "#F00", }, { "value": 10.0, "color": "#00F", } ], -------------------- Legend Configuration -------------------- Colour-ramp styles support automatic legend generation. Automatic legend generation can be deactivated using the ``show_legend`` and ``url`` legend elements `common to all styles `_. (``show_legend`` is ``True`` by default for colour-ramp styles.) Legend Title ============ The legend title defaults to the style name, but can be over-ridden: E.g.:: "legend": { # Legend title will be display as "This is a nice legend" "title": "This is a nice legend" } You can optionally set ``units`` for the legend, which are placed in parentheses after the title. The default is to not display units:: "legend": { # Legend title will be display as "This is a nice legend(%)" "title": "This is a nice legend", "units": "%" } Legend Range ============ The legend range defaults to the `range <#ramp-scale-range>`_ for the default colour ramp or `MatPlotLib color ramps <#mpl_ramp>`_. For `manual colour ramps <#manual-color-ramp>`_, the default range is between the values of first and last colour point definitions in the ramp, **excluding** any leading or trailing colour points that are full transparent (alpha=0.0). To override the default range, use the ``begin`` and/or ``end`` entries in the ``legend`` section. They may be set using integers, numeric strings or floats. The vaguries of floating point arithmetic can cause unexpected behaviour with tick generation (discussed below), so it is strongly recommended to use numeric strings or integers. E.g.:: # Integers, OK "legend": { "begin": 0, "end": 99, }, # Non-integers # avoid floats as they may cause issues with tick generation. # Use numeric strings instead, like this: "legend": { "begin": "0.0", "end": "0.3", }, Legend Ticks ============ "Ticks" are the labeled points along the ramp legend. The default behaviour is to have exactly two ticks, at the minimum and maximum values. This can be over-ridden by any of the following alternative methods: Regularly spaced ticks, by size (ticks_every) +++++++++++++++++++++++++++++++++++++++++++++ Ticks are placed at steps of the indicated size, starting from the beginning of the legend range. As with "begin" and "end", numeric strings should be used in preference to floats. E.g.:: "legend": { # Ticks at 0.0, 0.5 and 1.0 "begin": "0.0", "end": "1.0", "ticks_every": "0.5", } "legend": { # Ticks at 0.0, 0.3, 0.6 and 0.9 # Note that there will be no tick at the maximum position (1.0) "begin": "0.0", "end": "1.0", "ticks_every": "0.3", } Regularly spaced ticks, by count (tick_count) +++++++++++++++++++++++++++++++++++++++++++++ The indicated number of ticks are spread evenly along the legend. The count includes the "end" tick but not the "begin" tick. E.g.:: "legend": { # Tick at 0.0 only "begin": "0.0", "end": "1.0", "ticks_count": 0, } "legend": { # Ticks at 0.0 and 1.0 # This is the default behaviour if no tick generation # option is specified "begin": "0.0", "end": "1.0", "ticks_count": 1, } "legend": { # Ticks at 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 "begin": "0.0", "end": "1.0", "ticks_count": 5, } Explicit ticks (ticks) ++++++++++++++++++++++ Tick locations can also be specified explicitly by setting ``ticks`` to a list of values. Again, please use numeric strings rather than floats. E.g. the following are not possible with tick_count or ticks_every:: "legend": { # No ticks at all "begin": "0.0", "end": "1.0", "ticks": [] } "legend": { # Evenly spaced ticks with no ticks on the extremes of the range. "begin": "0.0", "end": "1.0", "ticks": ["0.2", "0.4", "0.5", "0.6", "0.8"] } "legend": { # Unevenly spaced ticks "begin": "-5.0", "end": "5.0", "ticks": ["-5.0", "-1.0", "0.0", "1.0", "5.0"], } Tick Labels =========== Tick labels can be customised as follows: decimal_places ++++++++++++++ The number of decimal places to display in tick labels. The default is one. E.g.:: "legend": { # Tick labels: "0.00", "0.25", "0.50", "0.75", "1.00" "begin": "0.00", "end": "1.00", "ticks_every": "0.25", "decimal_places": 2 } "legend": { # Tick labels: "0", "1", "2", "3", "4", "5" "begin": "0.0", "end": "5.0", "ticks_every": "1.0", "decimal_places": 0 } Prefixes and suffixes +++++++++++++++++++++ The "default" entry in the "tick_labels" table can set prefixes and suffixes to be added to all tick labels. E.g.:: "legend": { "begin": "0.0", "end": "1.0", "ticks_every": "0.2", "decimal_places": 1, "tick_labels": { # Surround every tick label in square brackets "default": { "prefix": "[", "suffix": "]", } } Over-riding labels for individual ticks +++++++++++++++++++++++++++++++++++++++ If a tick's default label (with no prefix or suffix) appears as a key in the ``tick_labels`` dictionary then the prefix, suffix or label of that tick label can be overridden. E.g.:: "legend": { "begin": "0.0", "end": "1.0", "ticks_every": "0.2", "decimal_places": 1, "tick_labels": { # Surround every tick label in square brackets "default": { "prefix": "[", "suffix": "]", }, # There is no "0.0" entry, so the 0.0 tick will be labelled "[0.0]" # The 0.2 tick will be labelled "(0.2)" "0.2": { "prefix": "(", "suffix": ")", }, # The 0.4 tick will be labelled "[foo]" # (Note the default prefix and suffix are still applied) "0.4": { "label": "foo", }, # The 0.6 tick will be labelled "bar" with no prefix or suffix "0.6": { "prefix": "", "label": "bar", "suffix": "", }, # The 0.8 tick will be labelled ":-)" "0.8": { "prefix": ":", "label": "-", "suffix": ")", }, # There is no "1.0" entry, so the 1.0 tick will be labelled "[1.0]" } Values passed to MatPlotLib =========================== Colour ramp auto-legends are created using the MatPlotLib library. The following values are passed directly to the MatPlotLib library. Please refer to the `MatPlotLib documentation `_ for further information. Image Size ++++++++++ The ``width`` and ``height`` values are passed to matplotlib to specify the size of the generated image. The image size defaults to 4 inches wide by 1.25 inches tall. The default dpi for MatPlotLib is 100, so this corresponds to 400x125 pixels unless you have over-ridden the default dpi. E.g.:: "legend": { "width": 4.5, "height": 2.1 } strip_location ++++++++++++++ The location of the coloured ramp strip within the legend image can be customised with the ``strip_location`` element. This should be a tuple of four floats which is passed directly to the MatPlotLib Figure.add_axes function. The four floats are expressed as fractions of the width or heigth (i.e. are numbers between 0.0 and 1.0). The values are interpreted as follows: [left, bottom, width, height]. The default value is [ 0.05, 0.5, 0.9, 0.15 ] E.g.:: "legend": { "strip_location": [ 0.1, 0.4, 0.8, 0.2 ] } MatPlotLib rc params ++++++++++++++++++++ Other MatPlotLib customisations (as they would appear in a .matplotlibrc file) can be specified with the optional ``rcParams`` element, defaulting to {}, meaning the MatPlotLib defaults for all options. For a full list of possible options refer to `the MatPlotLib documentation `__ E.g.:: "legend": { "rcParams": { "lines.linewidth": 2, "font.weight": "bold", }, } ------------------- Multi-Date Requests ------------------- Colour Ramp Styles support customised non-animated handlers for `multi-date requests `_ by providing for an aggregator function that converts the multi-date index data into a dateless index, and apply either the style's colour ramp (i.e. the same as the single-date case), or a separate colour ramp. pass_raw_data ============= The ``pass_raw_data`` entry controls what data is passed to the aggregator function: ``pass_raw_data == False`` (the default): The aggregator function is passed a time-dimensioned DataArray containing the output of the index function. ``pass_raw_data == True``: The aggregator function is passed a time-dimensioned Dataset, containing all of the declared needed bands. aggregator_function =================== The ``aggregator_function`` entry is required for colour ramp style multi-date handlers. It is a function defined using OWS's :doc:`function configuration format `. The first argument passed to the function depends on the value of the ``pass_raw_data`` element, as described above. The function should return an xarray DataArray with no time dimension, containing the data used as an input to the `multi-date handler's colour ramp <#multi-date-colour-ramps>`__. Multi-Date Colour Ramps ======================= Each multi-date handler has it's own colour ramp. It may be defined by any of the `colour ramp definition methods <#colour-ramps>`__ described above. Multi-Date Legend ================= A legend can be automatically generated for a multi-date handler. The ``legend`` section of a colour ramp style multi-date handler behaves the same as the single-date `legend section <#legend-configuration>`__ described above. feature_info_label ================== The multi-date aggregator function value will be returned in multi-date GetFeatureInfo requests for this style, using the label declared by the ``feature_info_label`` entry. E.g. :: # A simple index delta (difference) multi-date handler "multi_date": { # Only 2 dates makes sense for delta. "allowed_count_range": [2,2], # Calculating the difference "aggregator_function": { "function": "datacube_ows.band_utils.multi_date_delta", }, # The delta colour ramp. "mpl_ramp": "RdBu", "range": [-1.0, 1.0], "legend": { # Ticks at -1.0, -0.5, 0.0, 0.5, 1.0 "begin": "-1.0", "end": "1.0", "ticks_every": "0.5" }, # The feature info label. "feature_info_label": "ndvi_delta", }