diff --git a/datacube_ows/band_utils.py b/datacube_ows/band_utils.py index 97d27af7..7f1f7cd6 100644 --- a/datacube_ows/band_utils.py +++ b/datacube_ows/band_utils.py @@ -188,6 +188,17 @@ def multi_date_delta(data, time_direction=-1): def multi_date_pass(data): return data +def multi_date_raw_example(data, band1, band2, band_mapper=None): + if band_mapper: + band1 = band_mapper(band1) + band2 = band_mapper(band2) + data1, data2 = (data.sel(time=dt) for dt in data.coords["time"].values) + return ( + (data2[band1] - data1[band1]) - (data2[band2] - data1[band2]) + ) / ( + data1[band1] + data1[band2] + data2[band1] + data2[band2] + ) + @band_modulator @scalable diff --git a/datacube_ows/styles/component.py b/datacube_ows/styles/component.py index 1ea88a21..df7b6b75 100644 --- a/datacube_ows/styles/component.py +++ b/datacube_ows/styles/component.py @@ -163,7 +163,7 @@ def transform_single_date_data(self, data: "xarray.Dataset") -> "xarray.Dataset" else: imgband_data = imgband_component if imgband_data is None: - null_np = np.zeros(list(data.dims.values()), 'uint8') + null_np = np.zeros(list(data.dims.values()), 'float64') imgband_data = DataArray(null_np, data.coords, data.dims.keys()) if imgband != "alpha": imgband_data = self.compress_band(imgband, imgband_data) diff --git a/datacube_ows/styles/ramp.py b/datacube_ows/styles/ramp.py index bdacd8ce..25aeed27 100644 --- a/datacube_ows/styles/ramp.py +++ b/datacube_ows/styles/ramp.py @@ -574,9 +574,11 @@ def __init__(self, style: "ColorRampDef", cfg: CFG_DICT) -> None: if self.animate: self.feature_info_label: Optional[str] = None self.color_ramp = style.color_ramp + self.pass_raw_data = False else: self.feature_info_label = cast(Optional[str], cfg.get("feature_info_label", None)) self.color_ramp = ColorRamp(style, cfg, self.legend_cfg) + self.pass_raw_data = bool(cfg.get("pass_raw_data", False)) def transform_data(self, data: "xarray.Dataset") -> "xarray.Dataset": """ @@ -585,13 +587,17 @@ def transform_data(self, data: "xarray.Dataset") -> "xarray.Dataset": :param data: Raw data :return: RGBA image xarray. May have a time dimension """ - xformed_data = cast("ColorRampDef", self.style).apply_index(data) - agg = self.aggregator(xformed_data) + if self.pass_raw_data: + agg = self.aggregator(data) + else: + xformed_data = cast("ColorRampDef", self.style).apply_index(data) + agg = self.aggregator(xformed_data) return self.color_ramp.apply(agg) class Legend(RampLegendBase): def plot_name(self): return f"{self.style.product.name}_{self.style.name}_{self.style_or_mdh.min_count}" + # Register ColorRampDef as Style subclass. StyleDefBase.register_subclass(ColorRampDef, ("range", "color_ramp")) diff --git a/docs/cfg_colourramp_styles.rst b/docs/cfg_colourramp_styles.rst index ed76c7b9..1a044c2c 100644 --- a/docs/cfg_colourramp_styles.rst +++ b/docs/cfg_colourramp_styles.rst @@ -65,7 +65,7 @@ entry. index_function ++++++++++++++ -The `index_function` allows the user to declare a callback function +The ``index_function`` allows the user to declare a callback function to calculate the index value using OWS's `function configuration format `_. The function is expected to take an xarray Dataset containing all the @@ -76,12 +76,12 @@ an xarray Dataset containing the index value. A `small library `_ of general purpose band math functions -are provided in `datacube_ows.band_utils`. +are provided in ``datacube_ows.band_utils``. needed_bands list +++++++++++++++++ -The `needed_bands` entry must list the names (or aliases) of +The ``needed_bands`` entry must list the names (or aliases) of all the bands required by the `index_function <#index-function>`__. @@ -125,7 +125,7 @@ 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 +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. @@ -154,8 +154,8 @@ E.g.:: 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>`_. +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 @@ -218,9 +218,9 @@ Legend Configuration Colour-ramp styles support automatic legend generation. Automatic legend generation can be deactivated using the -`show_legend` and `url` legend elements +``show_legend`` and ``url`` legend elements `common to all styles `_. -(`show_legend` is `True` by default for colour-ramp styles.) +(``show_legend`` is ``True`` by default for colour-ramp styles.) Legend Title ============ @@ -421,7 +421,7 @@ 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 +in the ``tick_labels`` dictionary then the prefix, suffix or label of that tick label can be overridden. E.g.:: @@ -474,7 +474,7 @@ further information. Image Size ++++++++++ -The `width` and `height` values are passed to matplotlib to specify the 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 @@ -492,7 +492,7 @@ 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 +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. @@ -512,7 +512,7 @@ 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 +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 @@ -537,16 +537,28 @@ 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 +The ``aggregator_function`` entry is required for colour ramp style multi-date handlers. It is a function defined using OWS's `function configuration format `_. -The function is assumed to take a single xarray Dataset with a time dimension. -The value at each time slice is the output of the `index function <#index-function>`__ -at that time. The function should return an xarray Dataset with no time +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>`__. diff --git a/integration_tests/cfg/ows_test_cfg.py b/integration_tests/cfg/ows_test_cfg.py index a85441e2..d0ba5aa8 100644 --- a/integration_tests/cfg/ows_test_cfg.py +++ b/integration_tests/cfg/ows_test_cfg.py @@ -393,8 +393,14 @@ "allowed_count_range": [2, 2], "animate": False, "preserve_user_date_order": True, + "pass_raw_data": True, "aggregator_function": { - "function": "datacube_ows.band_utils.multi_date_delta", + "function": "datacube_ows.band_utils.multi_date_raw_example", + "mapped_bands": True, + "kwargs": { + "band1": "nir", + "band2": "red", + } }, "mpl_ramp": "RdYlBu", "range": [-1.0, 1.0], diff --git a/wordlist.txt b/wordlist.txt index 5493e3d5..5e776b22 100644 --- a/wordlist.txt +++ b/wordlist.txt @@ -37,6 +37,7 @@ audreyr australia auth autogenerate +autoupdate awk aws ba @@ -51,6 +52,7 @@ bd bda beb befce +benjimin bfa bitflag bitflags @@ -117,12 +119,14 @@ dde de dea deafrica +dependabot desc describecoverage DescribeCoverage dev df digitalearthafrica +dimensioned dir dns docstrings @@ -158,6 +162,7 @@ fdb fdba fde fe +FeatureInfo featurelisturls FeatureListURLs fqn @@ -166,6 +171,7 @@ func gda gdal geobase +geojson geomedian geoscience geoscienceaustralia @@ -187,6 +193,7 @@ gettext gettile GetTile gh +GHA github githubusercontent googlemap @@ -287,6 +294,7 @@ petrak pgdata pil pindge +pjonsson pki png po