I am trying to plot a las where I filtered objects, that have a first and a last return simultaneously (objects in the las file), onto a created dtm of the same las. I am able to produce a good result. However, the values in the legend resemble the calculated Z values and not the real height values of the object.

Here is my code for this:

las_kölau <- readLAS("path", filter = "-drop_z_below 0")
las <- retrieve_pulses(las_kölau)
las <- filter_firstlast(las)
las <- filter_poi(las, NumberOfReturns > 1)

las@data[, d := Z[1]-Z[2], by = pulseID]

d <- las@data$Z[1]-las@data$Z[2]
las <- filter_first(las)
las <- filter_poi(las, !is.na(d))

dtm <- grid_terrain(las_kölau, 0.5, algorithm = knnidw(k= 6L, p = 2))
plot(las, bg = "white", axis = TRUE, legend = TRUE, pal = gray(1:50/50)) |> add_dtm3d(dtm, col=brewer.pal(n = 9, name = "YlOrBr"))

This is the resulting plot: DTM and objects plotted

Unfortunately, the legend only shows the Z values of the las and not the real height values. When I try to normalise the two plots, they flatten out as expected and do not show terrain.

las_flat <- las-dtm
dtm_flat <- dtm - dtm
plot(las_flat, bg = "white", axis = TRUE, legend = TRUE, pal = gray(1:50/50)) |> add_dtm3d(dtm_flat, col=brewer.pal(n = 9, name = "YlOrBr"))

Resulting plot when normalising: Resulting plot when normalising

Can anybody help me with either plotting the legend of the normalized plot onto the original plot or help me how to manipulate the las data so it shows the actual object height and not the terrain height?

Also if anyone has any recommendations/remarks on anything, please mention them to me.

edit (26/09/2023, 17:44):

I have edited the normalised plot by emitting all pixels with a Z value < 0 so the legend will show no negative values by:

las_flat <- filter_poi(las_flat, Z >= 0)

1 Answer 1


I'm not sure I understood what you are trying to do. I think you want this:


LASfile <- system.file("extdata", "Topography.laz", package="lidR")
las = readLAS(LASfile)
dtm = rasterize_terrain(las, algorithm = tin())
las = normalize_height(las, dtm, add_lasattribute= TRUE)
zref = las$Zref
las$Zref = las$Z
las$Z = zref

plot(las, color = "Zref", legend = TRUE) |>  add_dtm3d(dtm)
  • This still results in the same problem that the normalisation and the dtm do not match when I plot them in 3D. When I plot the two together, the dtm is visualised above the point cloud (due to the subtraction of the dtm values in the normalisation process). The result I need would be the point cloud plotted onto the dtm with a legend that contains the normalised (real object-) height. I hope this helps clarifying the issue.
    – utz
    Sep 26, 2023 at 17:35
  • I see. See my edit.
    – JRR
    Sep 26, 2023 at 17:49
  • yes! It works now. Amazing, thank you so much!
    – utz
    Sep 26, 2023 at 21:21

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.