0

I am trying to write a function to calculate specific metrics which I can write to a data frame and then a .csv file to write 'reports' on each las file in a directory. I have tried the following code:

calculate_las_metrics <- function(chunk) 
{
  las <- readLAS(chunk)
  if (is.empty(las)) return(NULL)

# Calculate point density for las file
  total_point_density <- length(las$X)/st_area(las)

# extract unique classifications for las file
  classes <- unique(las$Classification)

# extract other information/descriptive data
  num_total_points <- length(las$X)
  num_returns_total <- sum(las$NumberOfReturns)
  num_of_1st_return <- chunk@data$Number.of.1st.return

# Create data frame of stats
  metrics_df_total <- data.frame(
  Classification = classes,
  Num_Points = num_points_total,
  Num_Returns = num_returns_total,
  Points_Per_Return = points_per_return_total,
  Point_Density = total_point_density,
  File = chunk$filename
  )
  return(metrics_df)
}
ctg <- readLAScatalog("path/to/las/files")
plan(multisession, workers = 8)
opt_chunk_buffer(ctg) <- 0
opt_output_files(ctg) <- paste0(tempdir(), "/{*}_metrics")
metrics <- catalog_apply(ctg, calculate_las_metrics)

This is currently returning:

Processing [-------------]   0% (0/856) eta:  ?s
Error: $ operator not defined for this S4 class

When I try and use las@data$X it returns this error:

Processing [-------------]   0% (0/856) eta:  ?s
Error: no applicable method for `@` applied to an object of class "data.table"

And when I have tried to just access it through chunk@data$X or chunk@data@X it returns this:

Processing [-------------]   0% (0/856) eta:  ?s
Error: no slot of name "data" for this object of class "LAScluster"

When I have checked the ctg or used summary(ctg) it has been fine and able to access the headers etc, and there isn't anything apparently wrong with the data when I access it using these methods. When I try and access the data and information on individual files in the catalog it appears fine. I have tried subsetting in a similar way to the answer for this problem Apply a function to a catalog but again it returns the "no slot of name data for this object of class LAScluster".

Am I missing something? Is it that I am combining how I access the information by using the individual las file and the 'chunk' for the ctg? I have tried to just use one or the other and it has still returned one of the previous errors.

I realise it could be my misinterpretation of how to use catalog_apply or use of the S4 class, but looking through the vignettes I can't see anything that would indicate I am access the data wrongly, and I am able to access the information in the console when I try, just not as a function.

Thanks for any advice or help anyone is able to give.

EDIT: Found that if the terra package is loaded it masks is.empty in lidR so for the function to work that line should be: if (lidR::is.empty(las)) return(NULL) For anyone like me who took a long time realising this.

3
  • 1
    Your code has dregs of an S4 sp object. With the modernization of spatial classes and depreciation of sp, rgdal, rgeos, and maptools the S4 classes, and slots, are no longer relevant. Oct 10th was when all packages needed to be compliant so, mostly this transition happened awhile ago. Keep in mind that there is likely documentation floating around showing examples using old object types. Familiarize yourself with new spatial classes and lidR outputs. Oct 23, 2023 at 22:44
  • @JeffreyEvans Thanks for letting me know; my introduction to spatial analysis in R has been pretty rapid (plunged into deep end so to speak) so didn't realise the depreciation of listed packages had now happened. Do you know if a package being compliant means that it has to have updated documentation or is that something that can be fixed after the fact? Oct 24, 2023 at 12:55
  • 1
    Well, there is on-line documentation, which is anybody guess, and the packages vignettes and specific function help. One would hope that things are updated but, this is not always the case. The examples in help documents are used to check the package during CRAN submission so, they should be reliable but, this is not ensured in the vignettes. Oct 24, 2023 at 15:04

1 Answer 1

2

You cannot use chunk@data$Number.of.1st.return. Chunk is a LAscluster. This class is not documented and you know nothing about it. You only know that you can write las = readLAS(chunk) and use st_bbox(chunk). I also fixed many typos, error, missing variables and so on.

calculate_las_metrics <- function(chunk) 
{
  las <- readLAS(chunk)
  if (is.empty(las)) return(NULL)
  
  
  # Calculate point density for las file
  total_point_density <- density(las)
  
  # extract unique classifications for las file
  classes <- unique(las$Classification)
  
  # extract other information/descriptive data
  num_total_points <- npoints(las)
  #num_returns_total <- sum(las$NumberOfReturns) does not make sense. 
  num_of_1st_return <- las$`Number of points by return`[1]
  
  # Create data frame of stats
  metrics_df_total <- data.frame(
    Classification = classes,
    Num_Points = num_total_points,
    #Num_Returns = num_returns_total,
    #Points_Per_Return = points_per_return_total,
    num_of_1st_return = num_of_1st_return,
    Point_Density = total_point_density
  )
  
  return(metrics_df_total)
}
5
  • Thank you for editing the question to make it appropriate. I have dyslexia and often miss such things so I appreciate the patience and the kindness in helping rather than berating. Is there any plan to document the LAScluster class? I realise I misunderstood the use of chunk and simply thought it was a variable by which to refer to the ctg with rather than an actual class. Is there a way to access the ctg within the function (for instance getting Filename <- ctg$filenames)? Oct 24, 2023 at 12:53
  • 1
    There is no plan to document LAScluster because there is no need to expose the details to the users. There is no case where a user need to know anything about this class. Also, Filename <- ctg$filenames is meaningless in the general case because the filename is ill defined. The LAScatalog processing engine is generic and the points from a chunk (i.e. a region of the catalog) may come from various files in various proportion.
    – JRR
    Oct 24, 2023 at 12:57
  • I did not use the best example to illustrate my question. Could I use ctg$Max.X (for instance) within the function to record those coordinates in the data frame? Would that be acceptable coding practice or would it be better to extract that in a separate function or variable and append it to the data frame? Oct 24, 2023 at 13:44
  • 1
    Your function does not receive the LAScatalog. If you want the bounding box of the chunk without buffer you can use st_bbox(chunk). If you want to include the buffer you can use st_bbox(las). Anyway at this stage you are better to ask a new question defining clearly your intentions. I'm sure there is a better solution
    – JRR
    Oct 24, 2023 at 13:58
  • Pointing out that the function doesn't actually receive the ctg has helped, thank you. I wasn't aware it that by using readLAS within catalog_apply meant the function didn't receive the LAScatalog. Also explains why previous iterations of the function I wrote before coming here didn't work as I expected them. Oct 24, 2023 at 15:18

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.