2

I noticed a kind of "inconsistency" in the values returned from two user-defined functions. I tested on a tile of 200mx200m to return a raster of pixel size 50m (16 pixels)

In the following function, if the condition is satisfied, the function returns ONLY one value.

funcky <- function(x)
{
 if (max(x) < 22)
 return(max(x))
}
grd <- grid_metrics(lasca, funcky(Z), 50)

When the condition is not satisfied, NA values are returned.

> as.array(grd[[1]])
, , 1
 [,1] [,2] [,3] [,4]
[1,] 19.92 21.90 NA NA
[2,] NA 21.46 21.89 NA
[3,] NA 21.73 NA NA
[4,] NA NA NA NA

I expected the same logic to be applied when the function returns a list of values. For example,

funcky <- function(x)
{
 if (max(x) < 22)
 return(list(max(x), mean(x), min(x)))
}
grd <- grid_metrics(lasca, funcky(Z), 50)

But the values are not NA, they are 0s as shown below.

> as.array(grd[[1]])
, , 1
 [,1] [,2] [,3] [,4]
[1,] 19.92 21.90 0.00 0
[2,] 0.00 21.46 21.89 0
[3,] 0.00 21.73 0.00 0
[4,] 0.00 0.00 0.00 0
, , 2
 [,1] [,2] [,3] [,4]
[1,] 6.555234 7.434102 0.000000 0
[2,] 0.000000 5.038366 5.733465 0
[3,] 0.000000 8.699386 0.000000 0
[4,] 0.000000 0.000000 0.000000 0
, , 3
 [,1] [,2] [,3] [,4]
[1,] -0.83 -0.04 0.00 0
[2,] 0.00 -0.07 -0.09 0
[3,] 0.00 -0.07 0.00 0
[4,] 0.00 0.00 0.00 0

If the metrics can have negative values (skewness, for example), then these 0s could potentially be misleading, as is the case in the third layer. Is this behaviour alright?

Adding an else {return(NULL)} didn't make any difference. And adding else {return(list(NA,NA,NA))} generated an error:

Error: Column 1 of result for group 2 is type 'logical' but expecting type 'double'. Column types must be consistent for each group.
JRR
9,9341 gold badge16 silver badges32 bronze badges
asked Jul 27, 2020 at 22:19

1 Answer 1

3

Your example works even if it is not safe because funky returns NULL implicitly. The inconsistent behavior with 0s instead of NAs is a bug fixed in version 3.0.2 and probably introduced in v3.0.0 20 days before 3.0.2. Update lidR and it should work.

That being said it is not a good practice. It works because R is very permissive and allows bad coding practice. Adding an else statement was correct but grid_metrics uses data.table under the hood and is thus designed to be type safe. You cannot mix logical and numeric it won't be type casted automatically. In R NA is logical. So you were almost correct but using wrong types.

funcky <- function(x)
{
 if (max(x) < 22)
 return(list(max(x), mean(x), min(x)))
 else
 return(list(NA_real_, NA_real_, NA_real_)
}
answered Jul 28, 2020 at 1:00
2
  • 1
    Yes, updating to 3.0.2 worked. I wasn't aware of the data type NA_real_. Thanks for that! While improving some code, I have come across some 'best practices' for if-else and was curious about how grid-metrics handled it. I suppose it is a useful clarification. Commented Jul 28, 2020 at 12:52
  • 1
    This is not actually about best practices for if-else but about undefined behavior in functions. No matter the path taken in the code, a function should always explicitly return something. In your case funcky has an undefined behavior for x >= 22. Hopefully R handle such case natively with NULL and the behavior of grid_metrics is made in such a way that it works. But you should avoid undefined behaviors. Commented Jul 28, 2020 at 13:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.