Color gradient for elevation data in a XYZ plot with R and Lattice

时间秒杀一切 提交于 2019-12-20 00:22:54

问题


I have a bunch of XYZ data where X and Y are coordinates and Z is supposed to be the elevation (LiDAR points). I am trying to plot this point cloud with a gradient based on the Z value.

Here is what I have so far:

# Read the CSV file with the LiDAR point cloud (which was conveniently converted to CSV)
myData <- read.csv("./52I212_plot10.las.csv")
# We don't need all attributes, let's keep only X, Y and Z.
myData <- subset(myData, select=c(X,Y,Z))
# We want a normalized version of Z (between 0 and 1)
myData$normalZ <- (myData$Z-min(myData$Z))/(max(myData$Z)-min(myData$Z))
str(myData)

With this I try to create the plot with

library(lattice)
ramp <- colorRampPalette(c("lightblue", "red"))
cloud(myData$Z ~ myData$X + myData$Y, xlab="X", ylab="Y", zlab="Z",pch=20,
  col.point=ramp(10)[myData$normalZ*10]) 

I expected Z values to have one of ten possible colors between lightblue and red.

When I change the plot command to

cloud(myData$Z ~ myData$X + myData$Y, xlab="X", ylab="Y", zlab="Z",pch=20,
  col.point=gray(myData$normalZ))

I get something that is much closer to what I need:

I suspect I am doing something wrong on the color ramp, but cannot figure out what.

thanks in advance

Rafael

EDIT

This question: How to match vector values with colours from a colour ramp in R? helped me a lot, but I still don't understand what I did wrong. This code works:

myData$normalZ <- (myData$Z-min(myData$Z))/(max(myData$Z)-min(myData$Z))
ramp <- colorRamp(c("lightblue", "red"))
cols <- ramp(myData$normalZ)
cloud(myData$Z ~ myData$X + myData$Y, xlab="X", ylab="Y", zlab="Z",pch=20,
      col.point=rgb(cols,maxColorValue = 256))

Please point what could be changed on the original code to make it work -- I cannot figure out why in the first figure colors appear to be randomish.

thanks Rafael


回答1:


Can't confirm without data, but I think 0's are throwing you off. Your normalZ is between 0 and 1, so 10 * normalZ is between 0 and 10. You're passing these non-integers to [ and they get rounded down. (I had to look this up, but from ?"[": "Numeric values [of i] are coerced to integer as by as.integer (and hence truncated towards zero)".

Giving 0 (or anything less than 1) as a subset index messes with your color vector's length and hence how things match up:

ramp(10)[c(0, 0.4, 0.8, 1.2, 1.6)]
# [1] "#ACD8E5" "#ACD8E5"

and then the too-short vector gets recycled. So, your code will probably work with

col.point = ramp(10)[ceiling(myData$normalZ * 10)]



回答2:


There's a small bug in the mapping of z-values to indices in the color ramp.

library(lattice)

N <- 500
myData <- data.frame(X = runif(N,0,30),
                     Y = runif(N,0,30),
                     Z = runif(N,0,300))

myData$normalZ <- (myData$Z-min(myData$Z))/(max(myData$Z)-min(myData$Z))

ramp <- colorRampPalette(c("lightblue", "red"))

cloud(myData$Z ~ myData$X + myData$Y, xlab="X", ylab="Y", zlab="Z",pch=20,
      col.point=ramp(10)[myData$normalZ*10])

Here myData$normalZ*10 maps Z-values in (0,1) onto color indices (0,10). (The floating point values get truncated to integers when indexing.) But ramp(10) only returns 10 (not 11) elements, and R vector indexing must start at 1 not 0, so for small Z-values NULL will be returned. Both effects ruin correct color interpolation.

The cloud then looks like this, with incorrect colouring along the Z-axis:

Correct interpolation like this

cloud(myData$Z ~ myData$X + myData$Y, xlab="X", ylab="Y", zlab="Z",pch=20,
      col.point=ramp(10)[myData$normalZ*9+1])

returns a result as expected:



来源:https://stackoverflow.com/questions/32597134/color-gradient-for-elevation-data-in-a-xyz-plot-with-r-and-lattice

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!