I am trying to extend the symbols available to me for plotting in 3D. In 2D, I use:
x1 <- sort(rnorm(10))
y1 <- rnorm(10)
z1 <- rnorm(10) + atan2(x1, y1)
x2 <- sort(rnorm(10))
y2 <- rnorm(10)
z2 <- rnorm(10) + atan2(x2, y2)
x3 <- sort(rnorm(10))
y3 <- rnorm(10)
z3 <- rnorm(10) + atan2(x3, y3)
new.styles <- -1*c(9818:9824, 9829, 9830, 9831)
In 2D, my plot works and gives the appropriate symbol:
plot(x1, y1, col="red", bg="red", pch=new.styles, cex = 2)
and the plot is here:
In 3D, however, the symbols do not get translated correctly.
rgl::plot3d(x1, y1, z1, col="red", bg="red", pch=new.styles, size = 10)
this yields:
The symbols are getting replaced with (one) circle.
I also tried with pch3d and got blank plots. However, pch3d does work with the "standard" plotting symbols.
rgl::pch3d(x1, y1, z1, col="red", bg="red", pch=10:19, size = 10)
I get the plot:
So, it appears to be that at least the symbols are not displaying in 3D. How can I display the preferred symbols?
I was able to only get a solution using text3d() -- hopefully there exists a better solution.
x1 <- sort(rnorm(12))
y1 <- rnorm(12)
z1 <- rnorm(12) + atan2(x1, y1)
x2 <- sort(rnorm(12))
y2 <- rnorm(12)
z2 <- rnorm(12) + atan2(x2, y2)
x3 <- sort(rnorm(12))
y3 <- rnorm(12)
z3 <- rnorm(12) + atan2(x3, y3)
new.styles <- c(9818:9824, 9829, 9830, 9831, 9832, 9827)
rgl::open3d()
pal.col <- RColorBrewer::brewer.pal(name = "Paired", n = 12)
for (i in 1:12)
rgl::text3d(x1[i], y1[i], z1[i], col=pal.col[i], text = intToUtf8(new.styles[i]), cex = 2, usePlotmath = TRUE)
rgl::box3d()
This yields the figure:
This may well be too complicated, hopefully there are better solutions out there.
This is the best I could do:
Set up file for texture/shape:
crown <- tempfile(pattern = "crown", fileext = ".png")
png(filename = crown)
plot(1,1, ann=FALSE, axes=FALSE, pch=-9818, cex = 40, col = 2)
dev.off()
Load package, define a function to plot the texture at a random point:
library(rgl)
xyz <- cbind(c(0,1,1,0), 0, c(0,0,1,1))
add_quad_point <- function(shape = crown, sd = 3) {
pos <- rnorm(3, sd = sd)
m <- sweep(xyz, MARGIN=2, STATS = pos, FUN = "+")
quads3d(m,
texture = shape,
texcoords = xyz[,c(1,3)],
col = "white",
specular = "black")
}
open3d()
replicate(10, add_quad_point())
axes3d()
## close3d()
Related
How can I can increase the font size of labels , x2, x1, x3, x4 in the plot produced based on the function varclus
set.seed(1)
x1 <- rnorm(200)
x2 <- rnorm(200)
x3 <- x1 + x2 + rnorm(200)
x4 <- x2 + rnorm(200)
x <- cbind(x1,x2,x3,x4)
v <- varclus(x, similarity="spear") # spearman is the default anyway
v # invokes print.varclus
print(round(v$sim,2))
plot(v)
Thanks.
plot.varclus internally calls plot.hclus as you can see by running:
getS3method("plot",class = 'varclus')
and it passes along the labels argument (and the ... argument(s)).
this includes a font scaling argument cex
so try:
plot(v,
cex = 1.5)
I'm plotting Ackley's function in R and I'd like to have an additional contour plot on the bottom of the plot. Here is what I'm doing:
library(fields)
ackley <- function(x1, x2) {
a <- 20
b <- 0.2
c <- (2*pi)
d <- 2
fofx1 <- -a*exp(-b*sqrt(1/d*sum(c(x1,x2)^2))) -
exp(sum( cos(c*c(x1,x2))/d))+a+exp(1)
return(fofx1)
}
Ackley <- Vectorize(ackley)
x1 <- seq(-4,4,length=150)
x2 <- seq(-4,4,length=150)
z <- outer(x1, x2, FUN="Ackley")
drape.plot( x1,x2,z, col=rev(rainbow(50)), horizontal = FALSE)
Is it possible with drape.plot() to add the contour or are there other alternatives?
The plot3D library offers a nice solution. See here for details.
library(plot3D)
ackley <- function(x1, x2) {
a <- 20
b <- 0.2
c <- (2*pi)
d <- 2
fofx1 <- -a*exp(-b*sqrt(1/d*sum(c(x1,x2)^2))) -
exp(sum( cos(c*c(x1,x2))/d))+a+exp(1)
return(fofx1)
}
Ackley <- Vectorize(ackley)
x1 <- seq(-4,4,length=150)
x2 <- seq(-4,4,length=150)
z <- outer(x1, x2, FUN="Ackley")
zlim <- c(0, 15)
persp3D(x=x1, y=x2, z = z, xlab = "x1", bty = "bl2",
ylab = "x2", zlab = "z", clab = "",
expand = 0.5, d = 2, phi = 20, theta = 30, resfac = 2,
contour = list(col = "grey", side = c("zmin", "z")),
zlim = zlim, colkey = list(side = 4, length = 0.5))
Is there a easy and efficient way to define a function like panel.xyplot (or rather panel.lines) that connects only two point (x1,y1) and (x2,y2) if x1 <= x2 and y1 <= y2? (Ideally, with all other properties are retained by label.xyplot(...))
I asked the same question a view month ago and the solution is great:
lattice, connect points only if the connection has a positive slope
Now it would be fine to have a real panel.xyplot like function so that I can use my own groups. It should work and plot like below, except the crossed lines.
I welcome suggestions.
I'm not sure I understand what you're after, but if I do, then I think this should work for any given group:
library(dplyr)
set.seed(1)
dat <- data.frame(x=1:10,y=sample(1:10))
dat <- mutate(dat, x0 = x, y0 = y, x1 = lead(x), y1 = lead(y), slope = (x1 - x0)/(y1 - y0))
with(dat, plot(x, y))
with(dat[1:nrow(dat) - 1,], segments(x0 = x0, y0 = y0, x1 = x1, y1 = y1,
col = ifelse(slope >= 0, "black", "white"))) # This bit gets makes line-drawing conditional
Here's what I get from that:
And here's a version for grouped data that doesn't depend on lattice:
dat2 <- data.frame(x = rep(seq(10), 10),
y = sample(1:10, size = 100, replace = TRUE),
indx = rep(seq(10), each = 10))
dat2g <- dat2 %>%
group_by(indx) %>%
mutate(., x0 = x, y0 = y, x1 = lead(x), y1 = lead(y), slope = (x1 - x0)/(y1 - y0))
plotit <- function(group) {
require(dplyr)
datsub <- filter(dat2g, indx == group)
with(datsub, plot(x, y, main = group))
with(datsub[1:nrow(datsub) - 1,], segments(x0 = x0, y0 = y0, x1 = x1, y1 = y1, col = ifelse(slope >= 0, "black", "white")))
}
par(mfrow=c( floor(sqrt(max(dat2g$indx))), ceiling(sqrt(max(dat2g$indx)))))
par(mai=c(0.5,0.5,0.5,0.25))
for (i in 1:length(unique(dat2g$indx))) { plotit(i) }
Here's the plot output from that process. It could use fine-tuning, but I think it's what you're after?
Could you give me an example on how to use rgl to plot 3 variables at the axes x, y and z and a fourth one with different colours?
thanks
You use a combination of persp and colour according to a separate function. Here's some example code:
## Create a simple surface f(x,y) = -x^2 - y^2
## Colour the surface according to x^2 only
nx = 31; ny = 31
x = seq(-1, 1, length = nx)
y = seq(-1, 1, length = ny)
z = outer(x, y, function(x,y) -x^2 -y^2)
## Fourth dim
z_col = outer(x, y, function(x,y) x^2)
## Average the values at the corner of each facet
## and scale to a value in [0, 1]. We will use this
## to select a gray for colouring the facet.
hgt = 0.25 * (z_col[-nx,-ny] + z_col[-1,-ny] + z_col[-nx,-1] + z_col[-1,-1])
hgt = (hgt - min(hgt))/ (max(hgt) - min(hgt))
## Plot the surface with the specified facet colours.
persp(x, y, z, col = gray(1 - hgt))
persp(x, y, z, col=cm.colors(32)[floor(31*hgt+1)], theta=-35, phi=10)
This gives:
RGL
It's fairly straightforward to use the above technique with the rgl library:
library(rgl)
## Generate the data using the above commands
## New window
open3d()
## clear scene:
clear3d("all")
## setup env:
bg3d(color="#887777")
light3d()
surface3d(x, y, z, color=cm.colors(32)[floor(31*hgt+1)], alpha=0.5)
There is an example in ?plot3d if you are talking about plotting points in a 3d space and colouring them:
x <- sort(rnorm(1000))
y <- rnorm(1000)
z <- rnorm(1000) + atan2(x,y)
plot3d(x, y, z, col=rainbow(1000))
But if you mean to colour the points by a 4th variable, say a grouping variable, then we can modify the example above to do this by creating a grouping variable
grp <- gl(5, 200) ## 5 groups 200 members each
## now select the colours we want
cols <- 1:5
## Now plot
plot3d(x, y, z, col=cols[grp])
OK, is this more what you want?
X <- 1:10
Y <- 1:10
## Z is now a 100 row object of X,Y combinations
Z <- expand.grid(X = X, Y = Y)
## Add in Z1, which is the 3rd variable
## X,Y,Z1 define the surface, which we colour according to
## 4th variable Z2
Z <- within(Z, {
Z1 <- 1.2 + (1.4 * X) + (-1.9 * Y)
Z2 <- 1.2 + (1.4 * X) - (1.2 * X^2) + (1.9 * Y) + (-1.3 * Y^2)
Z3 <- 1.2 + (1.4 * X) + (-1.9 * Y) + (-X^2) + (-Y^2)})
## show the data
head(Z)
## Set-up the rgl device
with(Z, plot3d(X, Y, Z1, type = "n"))
## Need a scale for Z2 to display as colours
## Here I choose 10 equally spaced colours from a palette
cols <- heat.colors(10)
## Break Z2 into 10 equal regions
cuts <- with(Z, cut(Z2, breaks = 10))
## Add in the surface, colouring by Z2
with(Z, surface3d(1:10,1:10, matrix(Z1, ncol = 10),
color = cols[cuts], back = "fill"))
with(Z, points3d(X, Y, Z1, size = 5)) ## show grid X,Y,Z1
Here's a modification where the plane surface Z1 is curved (Z3).
## Set-up the rgl device plotting Z3, a curved surface
with(Z, plot3d(X, Y, Z3, type = "n"))
with(Z, surface3d(1:10,1:10, matrix(Z3, ncol = 10),
color = cols[cuts], back = "fill"))
The detail of what I did to get Z2 probably doesn't matter, but I tried to get something like the graph you linked to.
If I've still not got what you want, can you edit your Q with some example data and give us a better idea of what you want?
HTH
Take a look at example(points3d).
The r3d help page shows you how to draw axes.
x <- c(0, 10, 0, 0)
y <- c(0, 0, 100, 0)
z <- c(0, 0, 0, 1)
i <- c(1,2,1,3,1,4)
labels <- c("Origin", "X", "Y", "Z")
text3d(x,y,z,labels)
segments3d(x[i],y[i],z[i])
Now you add some points
dfr <- data.frame(x = 1:10, y = (1:10)^2, z = runif(10), col = rainbow(10))
with(dfr, points3d(x, y, z, col = col))
Could you give me an example on how to use rgl to plot 3 variables at the axes x, y and z and a fourth one with different colours?
thanks
You use a combination of persp and colour according to a separate function. Here's some example code:
## Create a simple surface f(x,y) = -x^2 - y^2
## Colour the surface according to x^2 only
nx = 31; ny = 31
x = seq(-1, 1, length = nx)
y = seq(-1, 1, length = ny)
z = outer(x, y, function(x,y) -x^2 -y^2)
## Fourth dim
z_col = outer(x, y, function(x,y) x^2)
## Average the values at the corner of each facet
## and scale to a value in [0, 1]. We will use this
## to select a gray for colouring the facet.
hgt = 0.25 * (z_col[-nx,-ny] + z_col[-1,-ny] + z_col[-nx,-1] + z_col[-1,-1])
hgt = (hgt - min(hgt))/ (max(hgt) - min(hgt))
## Plot the surface with the specified facet colours.
persp(x, y, z, col = gray(1 - hgt))
persp(x, y, z, col=cm.colors(32)[floor(31*hgt+1)], theta=-35, phi=10)
This gives:
RGL
It's fairly straightforward to use the above technique with the rgl library:
library(rgl)
## Generate the data using the above commands
## New window
open3d()
## clear scene:
clear3d("all")
## setup env:
bg3d(color="#887777")
light3d()
surface3d(x, y, z, color=cm.colors(32)[floor(31*hgt+1)], alpha=0.5)
There is an example in ?plot3d if you are talking about plotting points in a 3d space and colouring them:
x <- sort(rnorm(1000))
y <- rnorm(1000)
z <- rnorm(1000) + atan2(x,y)
plot3d(x, y, z, col=rainbow(1000))
But if you mean to colour the points by a 4th variable, say a grouping variable, then we can modify the example above to do this by creating a grouping variable
grp <- gl(5, 200) ## 5 groups 200 members each
## now select the colours we want
cols <- 1:5
## Now plot
plot3d(x, y, z, col=cols[grp])
OK, is this more what you want?
X <- 1:10
Y <- 1:10
## Z is now a 100 row object of X,Y combinations
Z <- expand.grid(X = X, Y = Y)
## Add in Z1, which is the 3rd variable
## X,Y,Z1 define the surface, which we colour according to
## 4th variable Z2
Z <- within(Z, {
Z1 <- 1.2 + (1.4 * X) + (-1.9 * Y)
Z2 <- 1.2 + (1.4 * X) - (1.2 * X^2) + (1.9 * Y) + (-1.3 * Y^2)
Z3 <- 1.2 + (1.4 * X) + (-1.9 * Y) + (-X^2) + (-Y^2)})
## show the data
head(Z)
## Set-up the rgl device
with(Z, plot3d(X, Y, Z1, type = "n"))
## Need a scale for Z2 to display as colours
## Here I choose 10 equally spaced colours from a palette
cols <- heat.colors(10)
## Break Z2 into 10 equal regions
cuts <- with(Z, cut(Z2, breaks = 10))
## Add in the surface, colouring by Z2
with(Z, surface3d(1:10,1:10, matrix(Z1, ncol = 10),
color = cols[cuts], back = "fill"))
with(Z, points3d(X, Y, Z1, size = 5)) ## show grid X,Y,Z1
Here's a modification where the plane surface Z1 is curved (Z3).
## Set-up the rgl device plotting Z3, a curved surface
with(Z, plot3d(X, Y, Z3, type = "n"))
with(Z, surface3d(1:10,1:10, matrix(Z3, ncol = 10),
color = cols[cuts], back = "fill"))
The detail of what I did to get Z2 probably doesn't matter, but I tried to get something like the graph you linked to.
If I've still not got what you want, can you edit your Q with some example data and give us a better idea of what you want?
HTH
Take a look at example(points3d).
The r3d help page shows you how to draw axes.
x <- c(0, 10, 0, 0)
y <- c(0, 0, 100, 0)
z <- c(0, 0, 0, 1)
i <- c(1,2,1,3,1,4)
labels <- c("Origin", "X", "Y", "Z")
text3d(x,y,z,labels)
segments3d(x[i],y[i],z[i])
Now you add some points
dfr <- data.frame(x = 1:10, y = (1:10)^2, z = runif(10), col = rainbow(10))
with(dfr, points3d(x, y, z, col = col))