Closed ptompalski closed 3 years ago
I do agree, and it is more or less already planned.
The way lidR is built implies a lot of work to achieve what you are asking because of the way lidR has been built (successive iteration and function additions). This is because all *_metrics()
functions are independents and do not share a common code base. I only implemented your grid_metrics()
request and I did it the dirty way to ensure minimal efforts in changing grid_metrics()
.
I started an important work for v4.0.0. I'll try to take advantage of the fact that I have to redesign stuff in depth to built more robust and versatile stuff around *_metrics()
. My idea is to design a master layout_metrics()
function that accept any kind of layout (raster
, polygon
, stars
, ...). Then grid_metrics()
and so on will only be convenient wrapper functions around the same base of code. It looks like that in my plan:
# cloud_metrics
layout_metrics(las, layout = NULL)
layout_metrics(las, layout = st_bbox(las))
# grid_metrics
layout_metrics(las, layout = raster)
# plot_metrics
layout_metrics(las, layout = spatial_points)
# hexbin_metrics
hexagon_tessellation = sf::st_make_grid(..., square = FALSE)
layout_metrics(las, layout = hexagon_tessellation)
# polygon_metrics (no equivalent)
layout_metrics(las, layout = polygons)
# grid_metrics but also with support of rotated, sheared and rectilinear grids
layout_metrics(las, layout = stars)
If layout_metrics()
supports by_echo
then by inheritance every other function will too. That's my plan
Thanks, JR, all of this makes sense of course.
So I worked on it today and I came with something very modular and very powerful driven by a single core code easily extendable. That's very promising:
library(lidR)
LASfile <- system.file("extdata", "MixedConifer.laz", package="lidR")
las = readLAS(LASfile)
Equivalent (but more versatile) to grid_metrics()
layout = raster::raster(extent(las), nrow = 10, ncol = 10)
u = layout_metrics(las, ~list(maxz = max(Z)), layout)
v = layout_metrics(las, ~list(maxz = max(Z)), layout, by_echo = c("all", "single"))
w = layout_metrics(las, ~list(maxz = max(Z), minz = min(Z)), layout, by_echo = c("all", "single"))
x = grid_metrics(las, ~list(maxz = max(Z), minz = min(Z)), 10, by_echo = c("single", "multiple"))
plot(x, col = height.colors(25))
Equivalent (but more versatile) to cloud_metrics()
layout = st_bbox(las)
u = layout_metrics(las, ~list(maxz = max(Z)), layout)
v = layout_metrics(las, ~list(maxz = max(Z)), layout, by_echo = c("all", "single"))
v = layout_metrics(las, ~list(maxz = max(Z), minz = min(Z)), layout, by_echo = c("all", "single"))
x = cloud_metrics(las, ~list(maxz = max(Z), minz = min(Z)), by_echo = c("single", "multiple"))
print(x)
#> $maxz.single
#> [1] 32.07
#>
#> $minz.single
#> [1] 0
#>
#> $maxz.multiple
#> [1] 31.94
#>
#> $minz.multiple
#> [1] 3.02
Does not support yet rotated, sheared and rectilinear grids but will be very versatile
layout = lidR:::st_grid_layout(las, 10)
u = layout_metrics(las, ~list(maxz = max(Z)), layout)
v = layout_metrics(las, ~list(maxz = max(Z)), layout, by_echo = c("all", "single"))
w = layout_metrics(las, ~list(maxz = max(Z), minz = min(Z)), layout, by_echo = c("all", "single"))
plot(w)
#> downsample set to c(0,0,1)
Drives tree_metrics()
or voxel_metrics()
and anything we can imagine
layout = las$treeID
u = layout_metrics(las, ~list(maxz = max(Z)), layout)
v = layout_metrics(las, ~list(maxz = max(Z)), layout, by_echo = c("all", "single"))
w = layout_metrics(las, ~list(maxz = max(Z), minz = min(Z)), layout, by_echo = c("all", "single"))
x = voxel_metrics(las, ~list(avgi = mean(Intensity)), res = 5, by_echo = c("all", "single"))
y = tree_metrics(las, ~list(avgi = mean(Intensity)), by_echo = c("all", "single"))
spplot(y)
Many possible application including hexagon_metrics()
sfc = sf::st_as_sfc(st_bbox(las))
layout = sf::st_make_grid(sfc, cellsize = 10, square = FALSE)
u = layout_metrics(las, ~list(maxz = max(Z)), layout)
v = layout_metrics(las, ~list(maxz = max(Z)), layout, by_echo = c("all", "single"))
w = layout_metrics(las, ~list(maxz = max(Z), minz = min(Z)), layout, by_echo = c("all", "single"))
plot(w)
layout = layout[sample(1:length(layout), 15)]
u = layout_metrics(las, ~list(maxz = max(Z)), layout)
plot(u)
JR this is fantastic.
Can I run it myself? Is it in devel
already?
My only suggestion would be to use a different name for the function instead of layout_metrics()
(and to keep function names somewhat consistent). If we try to use verb-noun style as with some other functions, then perhaps something like calculate_metrics()
is better? (or calc_metrics()
to make it shorter).
No you can't test that yet it is not in devel. It is in my local branch v4.0.0
in which I'm removing sp
and raster
based code. But I can put it online if you want.
I don't understand your problem with the name. layout_metrics
seems consistent with grid_metrics
, cloud_metrics
, plot_metrics
, voxel_metrics
, point_metrics
. And I will probably introduce hexagon_metrics
and polygon_metrics
I pushed a pre-pre-pre-alpha version of lidR 4.0.0
in the branch v4
. All functions have filter
and by_echo
. They all share the same core code. This gave me so much work and troubles :smile: . See changelog.
cloud_metrics
plot_metrics
pixel_metrics
hexagon_metrics
polygon_metrics
crown_metrics
voxel_metrics
template_metrics
JR, the new
by_echo
parameter ingrid_metrics()
is great, thanks for adding that functionality!I think it is also needed in at least some of the other metrics functions. For example, when working on ABA predictions, the same sets of metrics are calculated for plots and for wall-to-wall rasters. If a user decides to use only first returns for wall-to-wall with
grid_metrics()
, they will also want to do the same when runningplot_metrics()
and possiblycloud_metrics()
,tree_metrics()
etc.