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?
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))
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
.
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)
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()]))
})
É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")
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")
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")
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")
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)
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();