I'm trying to plot the two circumferences with dimensions xy together with the 3d plot and colour the intersection of the two circles, how can I do that?
# objective function
x <- seq(-1,1,.1)
y <- seq(-1,1,.1)
z <- x^2 + y^2
library(scatterplot3d)
library(plotrix)
scatterplot3d(x,y,z,pch=19,color="royalblue4")
draw.circle (1,1,1)
draw.circle (1,-1,1)
I'm not really into mathematic stuff, but I'll post as answer because it might be of use and, also, is too big for a comment. Excuse any ignorance of mine, though, if I post nonsense.
#your data
library(scatterplot3d)
x <- seq(-1,1,.1)
y <- seq(-1,1,.1)
z <- x^2 + y^2
ang = 60 #angle of the 3D plot. experiment with different values
#your 3D plot, with extended xx', yy' limits
sp3d <- scatterplot3d(x, y, z, pch=19, color="royalblue4",
xlim = c(-1, 3), ylim = c(-3, 3), angle = ang)
#to use parametric equations of circles
f <- seq(-2*pi, 2*pi, 0.1)
#circle1
sp3d$points(x = 1 + 1*cos(f), y = 1 + 1*sin(f), z = rep(0, length(f)), type = "l")
#circle2
sp3d$points(x = 1 + 1*cos(f), y = -1 + 1*sin(f), z = rep(0, length(f)), type = "l")
The plot is:
Related
So I have this code that produces the exact surface
f = function(x, y){
z = ((x^2)+(3*y^2))*exp(-(x^2)-(y^2))
}
plot3d(f, col = colorRampPalette(c("blue", "white")),
xlab = "X", ylab = "Y", zlab = "Z",
xlim = c(-3, 3), ylim = c(-3, 3),
aspect = c(1, 1, 0.5))
Giving the following plot:
Now I have some code that does a random walk metropolis algorithm to reproduce the above image. I think it works as if I do another plot of these calculated values I get the next image with 500 points. Here is the code
open3d()
plot3d(x0, y0, f(x0, y0), type = "p")
Which gives the following plot:
I know it's hard looking at this still image but being able to rotate the sampling is working.
Now here is my question: How can I use plot3d() so that I can have a surface that connects all these points and gives a more jagged representation of the exact plot? Or how can I have each point in the z axis as a bar from the xy plane? I just want something more 3 dimensional than points and I can't find how to do this.
Thanks for your help
You can do this by triangulating the surface. You don't give us your actual data, but I can create some similar data using
f = function(x, y){
z = ((x^2)+(3*y^2))*exp(-(x^2)-(y^2))
}
x <- runif(500, -3, 3)
y <- runif(500, -3, 3)
z <- f(x, y)
Then the plotting is done using the method in ?persp3d.deldir:
library(deldir)
library(rgl)
col <- colorRampPalette(c("blue", "white"))(20)[1 + round(19*(z - min(z))/diff(range(z)))]
dxyz <- deldir::deldir(x, y, z = z, suppressMsge = TRUE)
persp3d(dxyz, col = col, front = "lines", back = "lines")
This might need some cosmetic fixes, e.g.
aspect3d(2, 2, 1)
After some rotation, this gives me the following plot:
I'm not sure to understand what you want. If my understanding is correct, here is a solution. Define a parametric representation of your surface:
fx <- function(u,v) u
fy <- function(u,v) v
fz <- function(u,v){
((u^2)+(3*v^2))*exp(-(u^2)-(v^2))
}
Let's say you have these points:
x0 <- seq(-3, 3, length.out = 20)
y0 <- seq(-3, 3, length.out = 20)
Then you can use the function parametric3d of the misc3d package, with the option fill=FALSE to get a wireframe:
library(misc3d)
parametric3d(fx, fy, fz, u=x0, v=y0,
color="blue", fill = FALSE)
Is it what you want?
To get some vertical bars, use the function segments3d of rgl:
i <- 8
bar <- rbind(c(x0[i],y0[i],0),c(x0[i],y0[i],f(x0[i],y0[i])))
segments3d(bar, color="red")
Here is a plot with only 50 points using my original code.
When I then apply what was said by Stéphane Laurent I then get this plot which feels too accurate when given the actual points I have
Perhaps you need to explain to me what is actually happening in the function parametric3d
I am looking to use the R plotly library to create a 3d surface plot of x,y,z coordinate data, similar to what is shown at the link below:
https://plot.ly/r/3d-surface-plots/
It appears that the plot_ly function requires the z coordinates to be in a matrix of dimensions x * y, as seen in datasets::volcano, used in the linked example. I'd appreciate some guidance on how to construct this matrix. Here is my sample x,y coordinate data:
## x coordinates
xSeq = seq(0, 1, .01)
## y coordinates
ySeq = seq(0, 1, .01)
## list with x, y coordinates
exmplList = list(x = xSeq, y = ySeq)
The z coordinates would be calculated via a formula from the x,y pairs (example formula used here is x + y). I've played around with something like:
exmplList = within(exmplList, z <- matrix(x + y, nrow = length(xSeq), ncol = length(ySeq)))
But that doesn't accomplish the pair combinations that I am trying to achieve.
Plotly surface needs a matrix so you could simply use this bit directly:
z = matrix(xSeq + ySeq, nrow = length(xSeq), ncol = length(ySeq))
Instead of doing a list. So, by running the following code:
## x coordinates
xSeq = seq(0, 1, 0.01)
## y coordinates
ySeq = seq(0, 1, 0.01)
## list with x, y coordinates
z = matrix(xSeq + ySeq, nrow = length(xSeq), ncol = length(ySeq))
fig = plot_ly(z = ~z) %>% add_surface()
fig
One obtains the following plot:
You might need to click and rotate a bit to see the plane. Hope it helps, cheers.
Is it possible to plot a plane, given the equation
x^2 + y^2 - 1.6z^2 + 1 = 0
with R?
It should look like this:
(Image source: https://commons.wikimedia.org/wiki/File:Zweischaliges_Hyperboloid.png)
What I've tried
library(rgl)
x = -20:20
xs = rep(x, 40)
y = -20:20
ys = rep(y, each=40)
z = (-(-1-x^2-y^2)/1.6)^0.5
plot3d(x=xs, y=ys, z=z)
This does plot the upper part, but I would like to see the lower part, too. Also, the plot doesn't look nice.
Answering the question I posed in my comment and providing what I think is a complete answer using rgl
library(rgl)
# define +ve function and plot it
zfun <- function(x,y) (-(-1-x^2-y^2)/1.6)^0.5
persp3d(zfun, c(-20,20), c(-20,20), n = 101)
# define x-y grid for second surface
xyvec <- seq(-20, 20, length.out = 101)
# calculate surface as -ve function and plot it
zmat <- -outer(xyvec, xyvec, zfun)
surface3d(xyvec, xyvec, zmat)
I would like to create a waterfall plot in R (XYYY) from my data.
So far, I use this code:
load("myData.RData")
ls()
dim(data)
##matrix to xyz coords
library(reshape2)
newData <- melt(data, id="Group.1")
dim(newData)
head(newData)
tail(newData)
newDataO <- newData[c(2,1,3)]
head(newDataO)
##color scale for z axis
myColorRamp <- function(colors, values) {
v <- (values - min(values))/diff(range(values))
x <- colorRamp(colors)(v)
rgb(x[,1], x[,2], x[,3], maxColorValue = 255)
}
cols <- myColorRamp(c("darkblue","yellow","darkorange","red","darkred"),newDataO$value)
##3D scatter
library(rgl)
plot3d(newDataO$variable, newDataO$Group.1, newDataO$value, xlab="", ylab="", zlab="", type="p", col=cols, box=FALSE, axes=FALSE)
rgl.postscript("persptrial_060514.eps","eps")
to get this plot:
https://dl.dropboxusercontent.com/u/14906265/persptrial_060514.jpg
I have also use this option in 2d with polygon but the result does not properly show the differential effect between both plots (left vs right).
I do not know whether something like persp3d could do the job but I am not familiar enough with writing code to achieve it. Any help will be very much appreciated.
It seems to me that the simplest way of doing a waterfall plot in R is to add all the lines manually in a loop.
library(rgl)
# Function to plot
f <- function(x, y) sin(10 * x * y) * cos(4 * y^3) + x
nx <- 30
ny <- 100
x <- seq(0, 1, length = nx)
y <- seq(0, 1, length = ny)
z <- outer(x, y, FUN = f)
# Plot function and add lines manually
surface3d(x, y, z, alpha = 0.4)
axes3d()
for (i in 1:nx) lines3d(x[i], y, z[i, ], col = 'white', lwd = 2)
I've been working on a rather complicated chart in R. I have a wireframe with a surface and points distributed in X,Y,Z space all over (e.g. under the surface and over it).
The problem is that the points that plot don't "look" like they are underneath the surface.
I am trying to figure out how best to visualize this chart to make the points look under the surface. Some sample code for the wireframe & cloud come from here: R-List Posting
The code in an example:
library(lattice)
surf <-
expand.grid(x = seq(-pi, pi, length = 50),
y = seq(-pi, pi, length = 50))
surf$z <-
with(surf, {
d <- 3 * sqrt(x^2 + y^2)
exp(-0.02 * d^2) * sin(d)
})
g <- surf
pts <- data.frame(x =rbind(2,2,2), y=rbind(-2,-2,-2), z=rbind(.5,0,-.5))
wireframe(z ~ x * y, g, aspect = c(1, .5),
drape=TRUE,
scales = list(arrows = FALSE),
pts = pts,
panel.3d.wireframe =
function(x, y, z,
xlim, ylim, zlim,
xlim.scaled, ylim.scaled, zlim.scaled,
pts,
...) {
panel.3dwire(x = x, y = y, z = z,
xlim = xlim,
ylim = ylim,
zlim = zlim,
xlim.scaled = xlim.scaled,
ylim.scaled = ylim.scaled,
zlim.scaled = zlim.scaled,
...)
xx <-
xlim.scaled[1] + diff(xlim.scaled) *
(pts$x - xlim[1]) / diff(xlim)
yy <-
ylim.scaled[1] + diff(ylim.scaled) *
(pts$y - ylim[1]) / diff(ylim)
zz <-
zlim.scaled[1] + diff(zlim.scaled) *
(pts$z - zlim[1]) / diff(zlim)
panel.3dscatter(x = xx,
y = yy,
z = zz,
xlim = xlim,
ylim = ylim,
zlim = zlim,
xlim.scaled = xlim.scaled,
ylim.scaled = ylim.scaled,
zlim.scaled = zlim.scaled,
...)
})
Looking at my example, the points in pts are in actually in vertical line where X,Y =(2,-2) and the z goes from .5 to -.5.
However, to my eye the third point doesn't look like it is under the surface, to it looks like it is at coordinates(2,-3,0).
Is this just my eye mis-interpreting this ?
Does anyone have a suggestion on how to make my points look more "3D" ? Perhaps muting the color of the point to make it look "under the surface" by using some sort of transparency on the surface ?
I tried making the colors of the points different (red for over the surface, blue for under the surface) but that does not really help the graph much.
This might get you started:
library(emdbook)
sfun <- function(x,y) {
d <- 3 * sqrt(x^2 + y^2)
exp(-0.02 * d^2) * sin(d)
}
cc <- curve3d(sfun(x,y),xlim=c(-pi,pi),ylim=c(-pi,pi),n=c(50,50),
sys3d="rgl")
colvec <- colorRampPalette(c("pink","white","lightblue"))(100)
with(cc,persp3d(x,y,z,col=colvec[cut(z,100)],alpha=0.5))
pts <- data.frame(x=c(2,2,2), y=c(-2,-2,-2), z=c(.5,0,-.5))
with(pts,spheres3d(x,y,z,col="blue",radius=0.1))
rgl.snapshot("rgltmp1.png")