spatstat / spatstat.geom

Sub-package of spatstat defining spatial data and spatial/geometrical operations
7 stars 4 forks source link

as.polygonal from mask window fails when mask contains NA values #6

Closed AB-Kent closed 2 years ago

AB-Kent commented 2 years ago

I ran into this when creating polygonal masks from matrices that had been clipped using raster::mask. It's fixable in client code by avoiding the NAs, but maybe as.polygonal should replace NA values in the mask with FALSE, as done in this reprex?

# Mask with NA values, e.g. from raster::mask
test = structure(c(NA, NA, NA, NA, NA, FALSE, FALSE, NA, NA, NA, FALSE, 
                   FALSE, NA, NA, NA, FALSE, FALSE, FALSE, NA, NA, FALSE, TRUE, 
                   TRUE, NA, NA), .Dim = c(5L, 5L))

test
#>      [,1]  [,2]  [,3]  [,4]  [,5]
#> [1,]   NA FALSE FALSE FALSE FALSE
#> [2,]   NA FALSE FALSE FALSE  TRUE
#> [3,]   NA    NA    NA FALSE  TRUE
#> [4,]   NA    NA    NA    NA    NA
#> [5,]   NA    NA    NA    NA    NA

# Fails
spatstat.geom::as.polygonal(spatstat.geom::owin(mask=test))
#> Error in spatstat.geom::as.polygonal(spatstat.geom::owin(mask = test)): Internal error: length(starts)= 1 , length(finishes)= 0

# Works if NAs are replaced with FALSE
test[is.na(test)] = FALSE
spatstat.geom::as.polygonal(spatstat.geom::owin(mask=test))
#> window: polygonal boundary
#> enclosing rectangle: [3.95, 5.05] x [0.95, 3.05] units

Created on 2021-11-29 by the reprex package (v2.0.1)

rubak commented 2 years ago

Thanks for the clear reproducible example. I will discuss with @baddstats whether we should put in an argument in as.polygonal()to handle logical masks with NA values. I need to test how other functions using masks are behaving with NA values.

baddstats commented 2 years ago

In the design of spatstat, a binary mask is a logical matrix, and NA entries are not permitted.

If I understand the example, it originated from another package which does allow NA entries in a mask.

Rather than changing the spatstat software specification to allow NA values in a mask (which could generate a lot of extra work and cause the package to slow down) it seems to me that the solution is that owin(mask=M) should test for NA entries in the matrix M and convert them to FALSE. Then in your example, the result of owin will always conform to the spatstat design, and as.polygonal will not fall over.

Probably as.mask should also be modified.

AB-Kent commented 2 years ago

I agree, changing owin to replace NA values is a better solution.

baddstats commented 2 years ago

OK. This is implemented in the current development version spatstat.geom 2.3-0.013 and will be submitted to CRAN soon as 2.3-1.

Thanks again for drawing this to our attention.