web-dev-qa-db-fra.com

Tracer les données 3D en R

J'ai un jeu de données 3D:

data = data.frame(
    x = rep( c(0.1, 0.2, 0.3, 0.4, 0.5), each=5),
    y = rep( c(1, 2, 3, 4, 5), 5)
)

data$z = runif(
    25,
    min = (data$x*data$y - 0.1 * (data$x*data$y)),
    max = (data$x*data$y + 0.1 * (data$x*data$y))
)

data
str(data)

Et je veux le tracer, mais les fonctions intégrées de R alwyas donnent l'erreur

augmentation des valeurs 'x' et 'y' attendues

# ### 3D Plots ######################################################
# built-in function always give the error
#    "increasing 'x' and 'y' values expected"
demo(image)
image(x = data$x, y = data$y, z = data$z)

demo(persp)
persp(data$x,data$y,data$z)

contour(data$x,data$y,data$z)

Lors de ma recherche sur Internet, j'ai constaté que ce message se produisait lorsque les combinaisons de valeurs X et Y n'étaient pas uniques. Mais ici ils sont uniques.

J'ai essayé d'autres bibliothèques et là ça fonctionne sans problèmes. Mais je n'aime pas le style par défaut des tracés (les fonctions intégrées doivent répondre à mes attentes).

# ### 3D Scatterplot ######################################################
# Nice plots without surface maps?
install.packages("scatterplot3d", dependencies = TRUE)
library(scatterplot3d)
scatterplot3d(x = data$x, y = data$y, z = data$z)

# ### 3D Scatterplot ######################################################
# Only to play around?
install.packages("rgl", dependencies = TRUE)
library(rgl)
plot3d(x = data$x, y = data$y, z = data$z)
lines3d(x = data$x, y = data$y, z = data$z)
surface3d(x = data$x, y = data$y, z = data$z)

Pourquoi mes jeux de données ne sont-ils pas acceptés par les fonctions intégrées?

44
R_User

Si vous travaillez avec des données "réelles" pour lesquelles il est impossible de garantir que les intervalles et la séquence de la grille augmentent ou sont uniques (espérons que le (x,y,z) _ les combinaisons sont au moins uniques, même si ces triples sont dupliqués), je recommanderais le paquet akima pour l’interpolation d’une grille irrégulière à une grille régulière.

En utilisant votre définition de data:

library(akima)
im <- with(data,interp(x,y,z))
with(im,image(x,y,z))

enter image description here

Et cela devrait fonctionner non seulement avec image mais également avec des fonctions similaires.

Notez que la grille par défaut à laquelle vos données sont mappées par akima::interp est défini par 40 intervalles égaux couvrant la plage de x et y valeurs:

> formals(akima::interp)[c("xo","yo")]
$xo
seq(min(x), max(x), length = 40)

$yo
seq(min(y), max(y), length = 40)

Mais bien sûr, cela peut être annulé en passant les arguments xo et yo à akima::interp.

23
hatmatrix

J'utilise le paquetage lattice pour presque tout ce que je trace dans R et il a un tracé correspondant à persp appelé wireframe. Soit data la façon dont Sven le définit.

wireframe(z ~ x * y, data=data)

wireframe plot

Ou que diriez-vous de cela (modification de la figure 6.3 dans livre de Deepanyan Sarkar ):

p <- wireframe(z ~ x * y, data=data)
npanel <- c(4, 2)
rotx <- c(-50, -80)
rotz <- seq(30, 300, length = npanel[1]+1)
update(p[rep(1, prod(npanel))], layout = npanel,
    panel = function(..., screen) {
        panel.wireframe(..., screen = list(z = rotz[current.column()],
                                           x = rotx[current.row()]))
    })

Multiple wireframe plots using panel and update

Mise à jour: Traçage de surfaces avec OpenGL

Étant donné que cet article continue d'attirer l'attention, je souhaite ajouter la méthode OpenGL pour créer également des graphiques 3-d (comme suggéré par @tucson ci-dessous). Nous devons d’abord reformater le jeu de données de xyz-tripplets en vecteurs d’axe x et y et une matrice z.

x <- 1:5/10
y <- 1:5
z <- x %o% y
z <- z + .2*z*runif(25) - .1*z

library(rgl)
persp3d(x, y, z, col="skyblue")

rgl::persp3d

Cette image peut être librement pivotée et redimensionnée à l'aide de la souris, ou modifiée à l'aide de commandes supplémentaires. Si vous en êtes satisfait, sauvegardez-le à l'aide de rgl.snapshot.

rgl.snapshot("myplot.png")
53
Backlin

Ajoutant aux solutions des autres, je voudrais suggérer l’utilisation du paquetage plotly pour R, car cela a bien fonctionné pour moi.

Ci-dessous, j'utilise l'ensemble de données reformaté suggéré ci-dessus, allant de xyz-tripplets aux vecteurs d'axe x et y et une matrice z:

x <- 1:5/10
y <- 1:5
z <- x %o% y
z <- z + .2*z*runif(25) - .1*z

library(plotly)
plot_ly(x=x,y=y,z=z, type="surface")

enter image description here

La surface rendue peut être tournée et redimensionnée à l'aide de la souris. Cela fonctionne assez bien dans RStudio.

Vous pouvez également l'essayer avec le jeu de données intégré volcano de R:

plot_ly(z=volcano, type="surface")

enter image description here

19
Megatron

Je pense que le code suivant est proche de ce que vous voulez

x    <- c(0.1, 0.2, 0.3, 0.4, 0.5)
y    <- c(1, 2, 3, 4, 5)
zfun <- function(a,b) {a*b * ( 0.9 + 0.2*runif(a*b) )}
z    <- outer(x, y, FUN="zfun")

Il donne des données comme ceci (notez que x et y augmentent tous les deux)

> x
[1] 0.1 0.2 0.3 0.4 0.5
> y
[1] 1 2 3 4 5
> z
          [,1]      [,2]      [,3]      [,4]      [,5]
[1,] 0.1037159 0.2123455 0.3244514 0.4106079 0.4777380
[2,] 0.2144338 0.4109414 0.5586709 0.7623481 0.9683732
[3,] 0.3138063 0.6015035 0.8308649 1.2713930 1.5498939
[4,] 0.4023375 0.8500672 1.3052275 1.4541517 1.9398106
[5,] 0.5146506 1.0295172 1.5257186 2.1753611 2.5046223

et un graphique comme

persp(x, y, z)

persp(x, y, z)

8
Henry

Vous ne savez pas pourquoi le code ci-dessus n'a pas fonctionné pour la bibliothèque rgl, mais le lien suivant présente un bon exemple avec la même bibliothèque. Exécutez le code dans R et vous obtiendrez un beau graphe 3d que vous pourrez retourner sous tous les angles .

http://statisticsr.blogspot.de/2008/10/some-r-functions.html

########################################################################
## another example of 3d plot from my personal reserach, use rgl library
########################################################################
# 3D visualization device system

library(rgl);
data(volcano)
dim(volcano)

peak.height <- volcano;
ppm.index <- (1:nrow(volcano));
sample.index <- (1:ncol(volcano));

zlim <- range(peak.height)
zlen <- zlim[2] - zlim[1] + 1
colorlut <- terrain.colors(zlen) # height color lookup table
col <- colorlut[(peak.height-zlim[1]+1)] # assign colors to heights for each point
open3d()

ppm.index1 <- ppm.index*zlim[2]/max(ppm.index);
sample.index1 <- sample.index*zlim[2]/max(sample.index)

title.name <- paste("plot3d ", "volcano", sep = "");
surface3d(ppm.index1, sample.index1, peak.height, color=col, back="lines", main = title.name);
grid3d(c("x", "y+", "z"), n =20)

sample.name <- paste("col.", 1:ncol(volcano), sep="");
sample.label <- as.integer(seq(1, length(sample.name), length = 5));

axis3d('y+',at = sample.index1[sample.label], sample.name[sample.label], cex = 0.3);
axis3d('y',at = sample.index1[sample.label], sample.name[sample.label], cex = 0.3)
axis3d('z',pos=c(0, 0, NA))

ppm.label <- as.integer(seq(1, length(ppm.index), length = 10));
axes3d('x', at=c(ppm.index1[ppm.label], 0, 0), abs(round(ppm.index[ppm.label], 2)), cex = 0.3);

title3d(main = title.name, sub = "test", xlab = "ppm", ylab = "samples", zlab = "peak")
rgl.bringtotop();
3
tucson