opengeospatial / ogcapi-coverages

OGC API - Coverages draft specification
https://ogcapi.ogc.org/coverages
Apache License 2.0
22 stars 13 forks source link

How to do the difference between two times? #191

Open joanma747 opened 2 weeks ago

joanma747 commented 2 weeks ago

I have a coverage that has connectivity maps for several years as a time series. Last is 2017 but this are also available for 1987, 1992, 1997, 2002, 2007 and 2012. With properties+filters we can do alot using mathematics among bands but, I do not see the way I can do one of the most common things in GIS: calculate the change between two time instances (a difference operation). Can we express this somehow? properties=Forest(time=2017)-Forest(time=2012)?

jerstlouis commented 2 weeks ago

I think this would call for subsetting functions/operators.

Something like:

properties=Slice(Forest, ['time'], [2017]) - Slice(Forest, ['time'], [2012])

where the first parameter is the field, the second the list of dimensions to slice on, and the last parameter the values.

We could have a similar Trim() function taking a low and high set of values. There could also be a shorthand form for temporal slicing:

properties=TSlice(Forest,2017)-TSlice(Forest, 2012)

joanma747 commented 2 weeks ago

We will test the following syntax"es" in ODC and get back

properties=b01 properties=b01-b02, b03-b04 properties=Slice((b8-b4)/(b8+b4), ['time'], ['2017-01-01']) - Slice((b8-b4)/(b8+b4), ['time'], ['2012-01-01']) <-- @jerstlouis likes this one properties=Slice('(b8-b4)/(b8+b4)', time, '"2017-01-01"-"2012-01-01"') <- Note that the '(b8-b4)/(b8+b4)' should be done before the time substraction.

Perform((b8 - b4)/(b8 + b4), Slice(thing, time, 2017) - Slice(thing, time, 2012)) --> how to implement this in practice: subset=time("2017";"2012") ---> ds=(b8 - b4)/(b8 + b4) -- > Slice(ds, time, 2017-2012))

joanma747 commented 2 weeks ago

In fact, a mixed syntax should also work:

http://localhost/cgi-bin/mmdc.py/collections/s2_level2a_granule/coverage?subset=E(422401.47:437401.47),N(4582942.45:4590742.45),time("2018-04-28")&subset-crs=[EPSG:32631]&crs=[EPSG:32631]&properties=(B08_10m-B04_10m)/(B08_10m%2BB04_10m)-Slice('(B08_10m-B04_10m)/(B08_10m%2BB04_10m)',['time'],['2018-04-18'])&filter=(SCL_20m=4) or (SCL_20m=5) or (SCL_20m=6)

The "First" date is imposed by time("2018-04-28"). The "Second" date is overwritten by the slice function with ['time'],['2018-04-18']

We can also think if there is a need to overwrite the filter adding a 4th parameter to slice:

Slice('(B08_10m-B04_10m)/(B08_10m%2BB04_10m)',['time'],['2018-04-18'],'(SCL_20m=4) or (SCL_20m=5) or (SCL_20m=6)') this way every slice can have a different filter.

The use of quotes is questionable but it is very practical in the python implementation.

jerstlouis commented 2 weeks ago

The use of quotes is questionable but it is very practical in the python implementation.

Yes, I do question it very strongly ;)

I really don't think there should be quotes there. Ideally there would be a way for your Python implementation to do exactly what it's doing right now with the expression losing those quotes.

this way every slice can have a different filter.

I would not mix the concept of filter here. The time is the dimension on which you're slicing, so it is a natural parameter of a slicing function. A filter predicate in a slicing function doesn't make sense to me. In case, if you wanted to do something like this, you would need a Filter() function taking a filter predicate, which you could use inside the Slice() function, similarly how we have this Slice() function for this more advanced subsetting use case instead of using the subset query parameter.

joanma747 commented 2 weeks ago

Ok, I spend some time creating a python function that adds internally the quotes, in preparation for the internal evaluation of the expression, making the quotes in the OGC API coverage URL unnecessary.

So final supported syntax is: https://callus.ddns.net/cgi-bin/mmdc.py/collections/s2_level2a_granule/coverage?subset=E(422401.47:437401.47),N(4582942.45:4590742.45),time(%222018-04-28%22)&subset-crs=[EPSG:32631]&crs=[EPSG:32631]&properties=(B08_10m-B04_10m)/(B08_10m%2BB04_10m)-Slice((B08_10m-B04_10m)/(B08_10m%2BB04_10m),['time'],['2018-04-18'])&filter=(SCL_20m=4)or(SCL_20m=5)or(SCL_20m=6)

BTW, I have made my development public, even if it is not finalized, so you can still find some "dirty tricks" in it. https://github.com/joanma747/OGCAPI_ODC