Rasters.jl icon indicating copy to clipboard operation
Rasters.jl copied to clipboard

Should `zonal` include a kwarg `if_all_missing`

Open alex-s-gardner opened this issue 6 months ago • 8 comments

The following returns an error as all data is missing and the maximum is being requested:

dX = X(1:10)
dY = Y(1:10)
 
ras = Raster(fill(NaN, (dX,dY)); missingval=NaN)

ext = Rasters.Extent((X=(2,9), Y=(2,9)))
Rasters.zonal(maximum, ras; of=ext, skipmissing=true)
ERROR: ArgumentError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
Stacktrace:

should a kwarg be added to zonal to tell it what to do when no valid data is found? This would eliminate the need for try/catch statements to catch this error.

alex-s-gardner avatar May 08 '25 17:05 alex-s-gardner

Right yes that's annoying.

Do you want a zero? Maybe an init keyword would help. Assumed to be some kind of identity like 0 for sum or 1 for prod, and only used if there are no other values. A missing is the other option that should work

rafaqz avatar May 08 '25 17:05 rafaqz

I think returning missing would make the most sense.

Not sure if that works for all possible reducing functions.

alex-s-gardner avatar May 08 '25 17:05 alex-s-gardner

Yes so in this case using init in maximum fixes it. Should we allow passing that? It pretty simple to do. If set to nothing we won't pass it in.

rafaqz avatar May 08 '25 17:05 rafaqz

~~Is init too specific? What about a custom reducing function?~~

ya, init looks like the standard way to do this

alex-s-gardner avatar May 08 '25 18:05 alex-s-gardner

I guess you have some registry function that tells you whether to pass init?

asinghvi17 avatar May 08 '25 18:05 asinghvi17

We could add an innerkwargs keyword argument to zonal which would take a NamedTuple and forward this as keyword arguments to the reduction function. And then in your use case you can do Rasters.zonal(maximum, ras; of=ext, skipmissing=true, innerkwargs=(init=0,))

This would be more flexible and adaptable to other reduction functions.

felixcremer avatar May 08 '25 20:05 felixcremer

But init=x is cleaner and close to universal

rafaqz avatar May 08 '25 21:05 rafaqz

I think in general an innerkwargs that gets passed to all functions is good, but we can special case init if we have a function registry that says which functions can use it. Can just be can_use_init(::Type{<: typeof(yourfunction)}) = true.

asinghvi17 avatar May 08 '25 21:05 asinghvi17