odc-tools icon indicating copy to clipboard operation
odc-tools copied to clipboard

Add time out functionality to `select_on_a_map`

Open robbibt opened this issue 5 years ago • 6 comments

Adding a time out functionality to select_on_a_map would allow us to implement testing on functions and notebooks that use interactive map selection. For example, if no user feedback was observed after X seconds, fall back to a default bounding box extent.

robbibt avatar Feb 19 '20 00:02 robbibt

@Kirill888

robbibt avatar Feb 19 '20 00:02 robbibt

@robbibt what would be a good way to specify default value to return? The output of select_on_a_map is a Geometry class which is a bit too painful to construct.

Options:

  1. Bounding box as a tuple of 4 values in lonlat notation compatible with datacube.utils.geometry.BoundingBox class
extents = select_on_a_map(default=(left, bottom, right, top))
  1. Dictionary of x|y or lon|lat ranges
extents = select_on_a_map(default={'x': (left, right), 
                                   'y': (bottom, top)})

To make is easier for testing I suggest following rules for timeout behaviour:

  1. If both default= is set and timeout= are supplied
    • Return value supplied in default= converted to Geometry after timeout is reached
    • OR return user selection if happens quickly enough
  2. If timeout= is set but not default=
    • Raise Exception when timeout is reached
  3. If default= is set but not timeout=
    • Check env variable ODC_MAP_SELECT_TIMEOUT= for the value of timeout=: block if unset, otherwise behave as in (1)

Kirill888 avatar Mar 02 '20 03:03 Kirill888

Hmm, that's a great question. Ideally we wouldn't want to create too much extra handling code further downstream for when the default is returned... does dc.load allow data to be loaded using the BoundingBox class or would it have to be converted into a Geometry object before it can be used?

Would it be possible to have a simple semi-hard-coded Geometry object that's defined somewhere within the select_on_a_map function so that a Geometry object is always returned (and therefore gives valid results in testing without additional handling), but which could be over-written by passing an alternative value to default? It could be a simple rectangle based on the center lat-lons that you already have to pass to centre the map...

The timeout behaviour rules make sense to me.

robbibt avatar Mar 02 '20 04:03 robbibt

E.g. something like:

from datacube.utils.geometry import Geometry, CRS

def _sample_geom(lat, lon, buffer=0.05, crs='EPSG:4326'):

    y_min = lat - buffer
    y_max = lat + buffer
    x_min = lon - buffer
    x_max = lon + buffer
    
    return Geometry({'type': 'Polygon',
                     'coordinates': [[(x_min, y_max),
                                      (x_min, y_min),
                                      (x_max, y_min),
                                      (x_max, y_max),
                                      (x_min, y_max)]]}, 
                    crs=CRS(crs))

_sample_geom(-20.37, 119.51)
Geometry(POLYGON ((119.46 -20.32,119.46 -20.42,119.56 -20.42,119.56 -20.32,119.46 -20.32)), EPSG:4326)

robbibt avatar Mar 02 '20 04:03 robbibt

@robbibt I do not think it's feasible to have a global default at the library level. If you want to avoid setting default extents per notebook that uses this function then you are better off augmenting test runner code to replace this function at run-time with something that immediately returns some global constant.

BoundingBox can not be used as part of dc.load directly as far as I can tell, Geometry objects can be used via geopolygon= parameter.

Kirill888 avatar Mar 02 '20 05:03 Kirill888

Yep, OK. We can always just wrap select_on_a_map inside a larger function where necessary that converts the default bounding box to a Geometry then does the rest of the analysis (similar to the current run_filmstrips_app func here)

robbibt avatar Mar 02 '20 05:03 robbibt