GeoscienceAustralia / dea-config

Config files for dea services
Apache License 2.0
16 stars 22 forks source link

Dynamic creation of related style definitions for OWS #549

Open valpesendorfer opened 4 years ago

valpesendorfer commented 4 years ago

We've been recently running into issues creating related style definitions for WMS layers served out of the ODC, where one style definition would work, and an identical one with few changes would throw an error.

After a discussion in Slack, the solution was to create a deep copy and modify the elements needed for the new style. There are a couple of examples here in this repo.

I thought this is a bit cumbersome and not practical if you need many definitions which are related, so I've created a little function wrapper to take care of this. In the slack discussion I've been asked to share it in this issue:

import copy

def copy_style(template, **kwargs):

    tem_copy = copy.deepcopy(template)

    for name, value in kwargs.items():
        try:
            if name == 'bands':

                if isinstance(value, list):
                    tem_copy['needed_bands'] = value
                    tem_copy['index_function']['kwargs'] = {f'band{ix+1}':band for ix, band in enumerate(value)}
                else:
                    tem_copy['needed_bands'] = [value]
                    tem_copy['index_function']['kwargs']['band'] = value
            else:
                tem_copy[name] = value

        except KeyError:
            raise ValueError(f'Could not assign {name} to style!')

    return tem_copy

Basically, the keywords are a 1:1 match, with the exception of bands, so multiple bands can be specified.

So, if you have a template like this:


style_template_singleband = {
    "name": "name",
    "title": "title",
    "abstract": "Abstract",
    "needed_bands": ["data"],
    "index_function": {
        "function": "datacube_ows.band_utils.single_band",
        "pass_product_cfg": True,
        "kwargs": {
            "band": "data",
        }
    },
    "color_ramp": [],
    "legend": {
        "title": "Legend Ttile",
        "radix_point": 0,
        "scale_by": 1,
        "major_ticks": 20,
        "units": "unitless"
    }
}

You can create a new style like

style_s1p = copy_style(
    template=style_template_singleband,
    name='s1p',
    title='SPI 1 Month',
    abstract='Standard Precipitation Index over 1 Month',
    bands='s1p',
    color_ramp=spi_color_ramp,
    )

Which then can be a template to a more closely related style.


Disclaimer:

I'm not a professional python programmer, and this function was created to mainly deal with the single band definitions that we use at the moment. I know this won't work with the multiband ones, and also it won't be able to replace nested elements aside the ones related to band.

SpacemanPaul commented 4 years ago

Missed this because it was added to dea-config instead of datacube-ows.

This is a great idea Val, I've been thinking about providing a similar utility function in ows. The way you are handling "bands" is very specific to the single band case, but the idea could be extended fairly easily.

SpacemanPaul commented 4 years ago

@valpesendorfer if you have time to have a look at the OWS PR https://github.com/opendatacube/datacube-ows/pull/429 I would appreciate your feedback.

I've basically taken your ideas and run with them - possibly too far. :smile:

valpesendorfer commented 3 years ago

@SpacemanPaul sorry for the delayed response, I'm only coming back now from a lengthy contract break.

Looks awesome, thanks for implementing it! I'll give it a spin real soon