José Lucas Safanelli José Lucas Safanelli - 2 months ago 10
R Question

lapply: producing several 3D scatter plots with different titles

I'm trying to put the element name in the title of the graphic when running lapply. The problem is that the names are not iterating, just the first name is showed in all the plots.

Data example and code:

if(!require(scatterplot3d)) {
install.packages("scatterplot3d"); require(scatterplot3d)}

head(palha_antes)
X.mm Y.mm Altura.mm Rugosidade.mm
1 0 0 198.421 24.677
2 20 0 189.377 33.721
3 40 0 199.212 23.886
4 60 0 196.857 26.241
5 80 0 193.048 30.050
6 100 0 204.922 18.176

tratamentos = list(palha_antes, palha_depois, exposto_antes, exposto_depois)

names = c("Tratamento com palha antes da chuva",
"Tratamento com palha depois da chuva",
"Tratamento sem palha antes da chuva",
"Tratamento sem palha depois da chuva")

names(tratamentos) <- names

par(mfrow = c(2,2))
lapply(tratamentos, function (x) {
scatterplot3d(as.numeric(unlist(x[1])), as.numeric(unlist(x[2])),
as.numeric(unlist(x[3])), xlab = "X (mm)",ylab = "Y (mm)",
main = lapply(names(tratamentos), function(y) y), zlab = "Altura (mm)", pch = 20)
})
par(mfrow = c(1,1))


The part
main = lapply(names(tratamentos), function(y) y)
does not run as it should: 1

If I put x as function of y
main = lapply(names(tratamentos), function(y) x)
, the plot get all the values of the the variable x, not the name. So, do you have any suggestion to solve this part of the code? Thank you.

Answer

Why do you need 2 lapply? The following works.

tratamentos = list(palha_antes, palha_depois, exposto_antes, exposto_depois)

## don't use "names"; that will mask function "names"
NAMES <- c("Tratamento com palha antes da chuva",
           "Tratamento com palha depois da chuva",
           "Tratamento sem palha antes da chuva",
           "Tratamento sem palha depois da chuva")

par(mfrow = c(2,2))
lapply(1:length(tratamentos), function (i) {
  scatterplot3d(tratamentos[[i]][[1]], tratamentos[[i]][[2]],
                tratamentos[[i]][[3]], xlab = "X (mm)", ylab = "Y (mm)",
                main = NAMES[i], zlab = "Altura (mm)", pch = 20)
})
par(mfrow = c(1,1))

Essentially there is no need to use lapply. A for loop is perfect:

par(mfrow = c(2,2))
for (i in 1:length(tratamentos)) {
  scatterplot3d(tratamentos[[i]][[1]], tratamentos[[i]][[2]],
                tratamentos[[i]][[3]], xlab = "X (mm)", ylab = "Y (mm)",
                main = NAMES[i], zlab = "Altura (mm)", pch = 20)
  }
par(mfrow = c(1,1))

Reproducible Example

set.seed(0)
d <- data.frame(x = rnorm(50), y = rnorm(50), z = rnorm(50))
lst <- list(d, d, d, d)
NAMES <- LETTERS[1:4]

## `for` loop
par(mfrow = c(2,2))
for (i in 1:length(lst)) {
  scatterplot3d(lst[[i]][[1]], lst[[i]][[2]],
                lst[[i]][[3]], xlab = "X (mm)", ylab = "Y (mm)",
                main = NAMES[i], zlab = "Altura (mm)", pch = 20)
  }
par(mfrow = c(1,1))

## `lapply`
par(mfrow = c(2,2))
lapply(1:length(lst), function (i) {
  scatterplot3d(lst[[i]][[1]], lst[[i]][[2]],
                lst[[i]][[3]], xlab = "X (mm)", ylab = "Y (mm)",
                main = NAMES[i], zlab = "Altura (mm)", pch = 20)
})
par(mfrow = c(1,1))

Note, scatterplot3d has returned values, so if you use lapply, you will see a long list printed onto your screen.

enter image description here


Comments on your code

  • You can use x[[1]] instead of unlist(x[1]); I also don't know what the extra as.numeric is for;
  • lapply(names(tratamentos), function(y) y) is just as.list(names(tratamentos)).