Plotting ellipsoids / oblate spheroids in rgl - r

I have been using rgl to plot spheres, but now I need to plot ellipsoids.
The package includes ellipse3d; however, this seems to be for fitting ellipsoids to data, using matrices and stuff I'm not very good at.
What I want is a simple way to plot ellipsoids, in a similar way to spheres, using the centre coordinates and the scales in each direction. Can anyone help me out?

If you don't need the ellipse rotated around the axes, then you can just use a diagonal matrix for x (this plots a sphere, and defines the virtual "axes" along the x, y, z axes) and use the centre and scale parameters to shift the location and change the proportions.
plot3d(ellipse3d(diag(3),centre=c(1,2,4),scale=c(1,2,5)))

There's one in my cda package,
library(cda)
library(rgl)
## single ellipsoid
plot3d(rgl.ellipsoid(a=2,b=1,c=5))
## multiple ellipsoids, translated and rotated
cl <- helix(0.5, 1, 36, delta=pi/6, n.smooth=1e3)
sizes <- equal_sizes(0.04,0.02,0.02,NROW(cl$positions))
rgl.ellipsoids(cl$positions, sizes, cl$angles, col="gold")

Related

Strange object in vector3d() graphic when using matlib + rgl

I'm trying to plot 3-dimensional vectors (x, y, z coordinates) onto a 3D coordinate system in R like in the picture below. Ideally, I would then like to construct 3d kernel density plots, also like in the image below.
Ideal result of vector plot and 3d kernel density plot
I have a matrix containing ~100 rows and one column for each coordinate (x, y , z). Initially, I tried arrow3D() from the plot3D package but I find the perspective to be sub-par, it's rather difficult to discern directions of the arrows from one perspective in the final plot. Next I tried the rgl package which gives me interactivity - great. Minimal working example:
library(rgl)
library(matlib)
data2 <- data.frame(replicate(6,rnorm(100))) #sample data set for minimum working example
colnames(data2) <- c("x_target", "y_target", "z_target", "x_start", "y_start", "z_start")
x1 <- data2$x_target - data2$x_start
y1 <- data2$y_target - data2$y_start
z1 <- data2$z_target - data2$z_start
vec <- (diag(6,3)) # coordinates for x, y and z axis
rownames(vec) <- c("X", "Y", "Z") # labels for x, y and z axis
z <- as.matrix((data.frame(x=x1, y=y1, z=z1)))
open3d()
vectors3d(vec, color=c(rep("black",3)), lwd=2, radius=1/25)
vectors3d(X=z, headlength=1/25)
(due to the random numbers generator the strange looking rods appear at different coordinates, not exactly like in the image i link to below)
The result of the code above is a version of the image link below. One set of coordinates produces a very strange looking more like rod object which is far longer then the coordinates would produce. If I plot the vectors individually, no such object is created. Anyone have any ideas why this happens? Also, if anyone has a tool (doesn't have to be R), that can create a 3D vector plot like in the first image, I'd be grateful. I find it to be very complicated in R, but I'm definitely a beginner.
Strange object to the right (long red rod that doesn't look like an arrow at all)
Thank you!
This is due to a bug in the matlib package, fixed in verson 0.9.2 of that package. I think you need to install it from Github instead of CRAN to get the bug fix:
devtools::install_github("friendly/matlib")
BTW, if you are using random numbers in a reproducible example, you can make it perfectly reproducible by something like
set.seed(123)
at the start (or some number other than 123). I saw reproducible problems with your example for set.seed(4).

Calculate area from Lat/Lon matrix or within a 50% contour for multiple polygons in R

I want to find the total area from multiple polygons within different contour lines from kernel densities (kde2d).
Here is an image of the kernel density and the 50% contour line. How do I calculate the area within the 50% contour line?
I also created a matrix of lat lon coordinates, which represents the points within this 50% contour line. Would it be easier to calculate the total area using these points.
Any suggestions would be greatly appreciated!
Once you have your coordinates in a cartesian system, and have done the kernel smoothing using those coordinates, you can use the contourLines function to get the coordinates of the lines, and then the areapl function from the splancs package to compute the area of each simple ring.
For example, using the example in help(kde2d):
attach(geyser)
plot(duration, waiting, xlim = c(0.5,6), ylim = c(40,100))
f1 <- kde2d(duration, waiting, n = 50, lims = c(0.5, 6, 40, 100))
image(f1)
contour(f1)
so that's our data set up - suppose we want the area in the 0.008 contour:
C8 = contourLines(f1,level=0.008)
length(C8)
[1] 3
Now C8 is a list of length 3. We need to apply the areapl function over each of these:
> sapply(C8,function(ring){areapl(cbind(ring$x,ring$y))})
[1] 14.65282 12.27329 14.75005
And we can obviously sum:
> sum(sapply(C8,function(ring){areapl(cbind(ring$x,ring$y))}))
[1] 41.67617
Now this only makes sense if the coordinates are cartesian, and if the contour lines are complete loops. If the 0.008 contour was near the edge then its possible for the contour to get clipped to the bounding box and then bad things happen. Check at least that the last point of each ring is the same as the first.

polar image plot, how to do it with R?

I cannot find a straightforward way to make a nice image plot in R, but in polar coordinates. I'm basically attempting to find a R equivalent for the 'polarplot3d' function in MATLAB. I've been playing around with ggplot2 package but without much luck. Am I missing a package that contains functionality for what I'm attempting? thanks in advance for any pointers.
Ok, I'm trying to be more clear about what I'm trying to do. Lets say I want to define a polar coordinate grid, increments in the radial direction are 50m and 2.5 degrees in theta. This should look like a dartboard.
My data (r and angle in below code) are correspond to a radial distance measure and an angle. My desired z-value is the counts of a bivariate histogram between r and angle within the increments described above defining the grid.
My data is like the following:
# synthetic data for angle and distance #
angle <- rnorm(500,mean=90,sd=15)
r <- rnorm(500,mean=700,sd=200)
# bivariate histogram #
observations <- table(cut(angle,breaks=c(seq(0,360,by=2.5))),cut(r,breaks=c(seq(0,1400,by=50))))
# the 'z' data are in observations for each bin of bivariate histogram #
# hot to plot a polar coord image? #
It's very slow to render on my system, but
library(reshape2)
library(ggplot2)
mm <- melt(counts)
ggplot(mm,aes(Var1,Var2,fill=value))+geom_tile()+coord_polar()
ggsave("polar1.png")
appears to work.
I think the following could work. Use mapproject() from the maproj library to transform my xy coordinates acording to a polar projection (or another), Then use as.image() (from fields package) function to build a image object from my new coordiantes and my Z values. Eventually use image.plot().
library("mapproj")
xyProj <- mapproject(x, y, projection="conic", parameters=-90)
library("fields")
im <- as.image(z, x=xyProj)
image.plot(im)

Calculating the volume under a surface

I have created a 3D plot (a surface) using wireframe function. I wonder if there is any functions by which I can calculate the volume under the surface in a 3D plot?
Here is a sample of my data plus the wrieframe syntax I used to create my 3D (surface) plot:
x1<-c(13,27,41,55,69,83,97,111,125,139)
x2<-c(27,55,83,111,139,166,194,222,250,278)
x3<-c(41,83,125,166,208,250,292,333,375,417)
x4<-c(55,111,166,222,278,333,389,445,500,556)
x5<-c(69,139,208,278,347,417,487,556,626,695)
x6<-c(83,166,250,333,417,500,584,667,751,834)
x7<-c(97,194,292,389,487,584,681,779,876,974)
x8<-c(111,222,333,445,556,667,779,890,1001,1113)
x9<-c(125,250,375,500,626,751,876,1001,1127,1252)
x10<-c(139,278,417,556,695,834,974,1113,1252,1391)
df<-data.frame(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10)
df.matrix<-as.matrix(df)
wireframe(df.matrix,
aspect = c(61/87, 0.4),scales=list(arrows=FALSE,cex=.5,tick.number="10",z=list(arrows=T)),ylim=c(1:10),xlab=expression(phi1),ylab="Percentile",zlab=" Loss",main="Random Classifier",
light.source = c(10,10,10),drape=T,col.regions = rainbow(100, s = 1, v = 1, start = 0, end = max(1,100 - 1)/100, alpha = 1),screen=list(z=-60,x=-60))
Note: my real data is a 100X100 matrix
Thanks
The data you are feeding to wireframe is a grid of values. Hence one estimate of the volume of whatever underlying surface this is approximating is the sum of the grid values multiplied by the grid cell areas. This is just like adding up the heights of histogram bars to get the number of values in your histogram.
The problem I see with you doing this on your data is that the cell areas are going to be in odd units - percentiles on one axis, phi on the other has unknown units, so your volume is going to have units of loss times units of percentile times units of phi.
This isn't a problem if you want to compare volumes of similar things on exactly the same grid, but if you have surfaces on different grids (different values of phi, or different percentiles) then you need to be careful.
Now, noting that wireframe doesn't draw like a 3d histogram would (looking like square tower blocks) this gives us another way to estimate the volume. Your 10x10 matrix is plotted as 9x9 squares. Divide each of those squares into triangles and then compute the volume of the 192 right truncated triangular prisms (I think this is what they are - they are equilateral triangular prisms with a right angle and one sloping end). The formula for that should be out there somewhere. Probably base area times height to the centroid of the triangle or something.
I thought maybe this would be in the raster package, but it isn't. There's code for computing the surface area but not the volume! I'm sure the raster maintainer would be happy to have some code for this!
If the points are arbitrary (ie, don't follow smooth function), it seems like you're looking for the volume of the convex hull (minimum surface) surrounding these points. One package to help you calculate this is alphashape3d.
You'll need a 3-column matrix of the coordinates to form the right type of object to make the calculation but it seems rather straight-forward.

Plotting lines between two points in 3D

I am writing an regression algorithm which tries to "capture" points inside boxes. The algorithm tries to keep the boxes as small as possible, so usually the edges/corners of the boxes go through points, which determines the size of the box.
Problem: I need graphical output of the boxes in R. In 2D it is easy to draw boxes with segments(), which draws a line between two points. So, with 4 segments I can draw a box:
plot(x,y,type="p")
segments(x1,y1,x2,y2)
I then tried both the scatterplot3d and plot3d package for 3D plotting. In 3D the segments() command is not working, as there is no additional z-component. I was surprised that apparently (to me) there is no adequate replacement in 3D for segments()
Is there an easy way to draw boxes / lines between two points when plotting in three dimensions ?
The scatterplot3d function returns information that will allow you to project (x,y,z) points into the relevant plane, as follows:
library(scatterplot3d)
x <- c(1,4,3,6,2,5)
y <- c(2,2,4,3,5,9)
z <- c(1,3,5,9,2,2)
s <- scatterplot3d(x,y,z)
## now draw a line between points 2 and 3
p2 <- s$xyz.convert(x[2],y[2],z[2])
p3 <- s$xyz.convert(x[3],y[3],z[3])
segments(p2$x,p2$y,p3$x,p3$y,lwd=2,col=2)
The rgl package is another way to go, and perhaps even easier (note that segments3d takes points in pairs from a vector)
plot3d(x,y,z)
segments3d(x[2:3],y[2:3],z[2:3],col=2,lwd=2)

Resources