I would like to plot two planes in a 3D plot. I have tried persp3d and it generates two planes. But instead of the whole two planes, I just want to show parts of them divided by the intersection line, i.e, "left" part of the blue plane, and "upper" part of the red plane. I tried xlim, ylim, but it seems my lims are not single values, but functions.
library(rgl)
x <- seq(-10, 10, length = 30)
y <- x
region = expand.grid(x=x, y=y)
z1 = region$x+2*region$y + 2
z2=3*region$x+region$y
persp3d(x,y,z1,col="steelblue")
persp3d(x,y,z2,col="red",add=TRUE)
grid = mesh(x,y)
z = with(grid,ifelse(x+2*y>3*x+y,x+2*y,3*x+y))
persp3D(z = z, x = x, y = y,col = NULL)
for (i in 1:900){
z[i] = ifelse(region$x[i]+2*region$y[i] + 2 >
3*region$x[i]+region$y[i],region$x[i]+2*region$y[i] + 2,3*region$x[i]+region$y[i])}
persp3d(x,y,z,col="steelblue")
This is inspired by Huang Rui's suggestion
How can I to plot a progressive walk from point to point?
Lets have p1 =[1,0], p2=[0,1], p3=[1,1]. Plot should first draw a line from p1 to p2 showing the direction, wait for a second, then draw another line from p2 to p3 and it goes on if you have more data.
The plot size should be first fixed to (0,1)^2. Correct output should look similar to this image:
Example plot
My code is this for now:
plot(x,y,xlim=range(x), ylim=range(y), xlab="x", ylab="y", main="Filled Plane",pch=16)
#lines(x,y,xlim=range(x),ylim=(y),pch=16)
for(i in 1:20){
arrows(x[i],y[i],x[i+1],y[i+1],length = 0.25, angle = 30, col = 1:3)
}
One option is to use arrows. Fist you need to create a plot giving the data you want. Then you can draw lines to connect your points.
Let say you have random uniform arrays of x,y. Set the limit to decide how many points you want to plot.
Although I placed the points immediately ( I could not place the grid properly otherwise) Hope it helps.
limit<- 50
x <- runif(limit)
y <- runif(limit)
plot(x,y, xlim=range(0,1), ylim=range(0,1),
xlab="x", ylab="y", main = "Random Walk")
grid(nx = 10, ny = 10, col = "lightgray", lty = "dotted",
lwd = par("lwd"), equilogs = TRUE)
for(i in 1:limit){
arrows(x[i],y[i],x[i+1],y[i+1], length = 0.1, angle = 20)
Sys.sleep(0.5)
}
I have created a 3d sphere with rgl.spheres() using rgl, and plotted two point on the surface of the sphere. Does anyone know how to draw an arc between these two point?
You'll have to calculate points along the arc, and use lines3d to draw the curve. You might want to move the arc a little bit outside
the sphere to avoid problems if they intersect: neither one is really
spherical, so intersections are likely to look ugly.
For example,
r <- 1.3
center <- matrix(1:3, ncol=3)
library(rgl)
open3d()
spheres3d(center, radius = r, col = "white")
# A couple of random points
pts <- matrix(rnorm(6, mean=c(center, center)), ncol = 3)
# Set the radius to 1.001*r
setlen <- function(pt) {
center + 1.001*r*(pt - center)/sqrt(sum((pt - center)^2))
}
pts <- t(apply(pts, 1, setlen))
points3d(pts, col = "black")
# Now draw the arc
n <- 20
frac <- seq(0, 1, len = n)
arc <- matrix(0, ncol = 3, nrow = n)
for (i in seq_along(frac)) {
# First a segment
arc[i,] <- frac[i]*pts[1,] + (1-frac[i])*pts[2,]
# Now set the radius
arc[i,] <- setlen(arc[i,])
}
lines3d(arc, col = "red")
This produces
Edited to add:
The very latest version of rgl (0.100.5, only currently available on R-forge) has a new function arc3d. With that version the code to draw the image can be simplified to
library(rgl)
open3d()
spheres3d(center, radius = r, col = "white")
points3d(pts, col = "black")
arc3d(pts[1,], pts[2,], center, col = "red")
If the points are at different distances from center, it will join them
with an arc from a logarithmic spiral instead of a circular arc.
I'm working with 3 dimensional coordinates data, which i'm plotting in a scatterplot, i have ~30.000 datapoints, and i've included the first 10 here so that you can reproduce it
library(rgl)
library(plot3D)
library(car)
df <- data.frame(meanX = c(147.34694,
173.89244,
135.73004,
121.93766,
109.72152,
92.53709,
165.46588,
169.77744,
127.01796,
99.34347),
meanY = c(140.40816,
110.99128,
134.56023,
164.18703,
166.04051,
155.97329,
105.29377,
104.42683,
130.17066,
155.99696),
avgDist = c(40.788118,
12.957329,
14.24348,
39.10424,
34.694258,
25.532335,
21.491695,
23.528944,
9.309201,
31.916879))
I've been using the scatter3d function to plot this
scatter3d(x = df$meanX, y = df$meanY, z = df$avgDist, surface = FALSE)
Now my "problem", is that I would like to have a 2d surface with an external image file overlayed onto it at z=0, and as a bonus, if i could project a heatmap/contours from the scatterplot data (meanX and meanY used for the contours) over that image as well, that would be great.
This is the image i'd like to have draped at z = 0:
http://i.imgur.com/m6j4q3M.png
That image was made with this ggplot:
map.colors <- colorRampPalette(c("green","yellow","red"))
densityPlot <- ggplot(direData, aes(x = meanX, y = ,meanY)) +
stat_density2d(geom="tile", aes(fill=..density.., alpha=sqrt(sqrt(..density..))), contour=FALSE, n=100) +
scale_alpha(range = c(0, 1.0)) + scale_fill_gradientn(colours = map.colors(5)) +
xlim(70,185) + ylim(70,185)
minimap <- readPNG('~/yasp/minimap.png')
densityPlot + annotation_raster(minimap, ymin = 70 ,ymax=185 ,xmin = 70,xmax = 185) +
stat_density2d(geom="tile", aes(fill=..density.., alpha=10*sqrt(..density..)), contour=FALSE, n=100)
Is there any way to do this? I've googled quite a bit for a solution but found no real way of doing this. I don't mind creating the image first in ggplot2 with the heatmap, saving that, and then using that as input for the surface draping, but it would of course be quite cool if it could all be done in one call to plot.
(2nd Edit) I try to write something better code and confirm two xy-coordinates are the same. ggplot2 theme with no axes or grid help me to plot only the panel region.
library(rgl); library(grid); library(gtable)
df <- data.frame(meanX = c(147.34694, 173.89244, 135.73004, 121.93766,
109.72152, 92.53709, 165.46588, 169.77744,
127.01796, 99.34347),
meanY = c(140.40816, 110.99128, 134.56023, 164.18703,
166.04051, 155.97329, 105.29377, 104.42683,
130.17066, 155.99696),
avgDist = c(40.788118, 12.957329, 14.24348, 39.10424,
34.694258, 25.532335, 21.491695,23.528944,
9.309201, 31.916879))
map.colors <- colorRampPalette(c("green","yellow","red"))
# set scale_*_continuous() to plot only the panel region. limits mean xlim (or ylim)
# change "tile" into "raster" because of making noise lines on my screen
densityPlot <- ggplot(df[,1:2], aes(x = meanX, y = ,meanY)) +
stat_density2d(geom="raster", aes(fill=..density.., alpha=sqrt(sqrt(..density..))), contour=FALSE, n=100) +
scale_alpha(range = c(0, 1.0)) + scale_fill_gradientn(colours = map.colors(5)) +
scale_x_continuous(limits=c(70,185), expand = c(0,0)) + scale_y_continuous(limits=c(70,185), expand = c(0,0)) +
geom_point(size=4) # to test XY-coordinate (black points on the map)
open3d()
plot3d( df, type="s", radius=1, col="red", axes=F,
xlim = c(70,185), ylim = c(70,185),
expand = 1 )
plot3d( df, type="h", col="blue", add=T ) # to test XY-coordinate (line segments from z = 0)
axes3d(c("x","y","z") )
show2d({ # show2d uses 2D plot function's output as a texture on a box.
grid.draw(gtable_filter(ggplotGrob(densityPlot), "panel"))
},
expand = 1 , texmipmap = F ) # texmipmap = F makes tone clear (not essential)
# I think this is clearly better than using a intermediate file,
# so I deleted related code. Thanks Mike !
How about this?
I stored your lined image file in a png in the local directory, there is probably a way to do that without an intermediate file, but I would ask that as a separate question.
Note that this is actually a simple case of texture mapping. The texture is saved in the gameshot.png file you specified. You could warp the text around a more complicated object by adding more points to the geometry and adjusting the texture map coordinates accordingly.
While they should not have been absolutely necessary here, I added texture map coordinates as it looked like the file and the data were not aligned by default - and in fact the gameshot.png file was displaying reversed. It looks to me like the png file you specified does not quite match the data, I think there is an inversion somewhere before you saved it.
library(rgl)
library(plot3D)
library(car)
df <- data.frame(meanX = c(147.34694, 173.89244, 135.73004, 121.93766,
109.72152, 92.53709, 165.46588, 169.77744,
127.01796, 99.34347),
meanY = c(140.40816, 110.99128, 134.56023, 164.18703,
166.04051, 155.97329, 105.29377, 104.42683,
130.17066, 155.99696),
avgDist = c(40.788118, 12.957329, 14.24348, 39.10424,
34.694258, 25.532335, 21.491695,23.528944,
9.309201, 31.916879))
car::scatter3d(x = df$meanX, y = df$meanY, z = df$avgDist, surface = FALSE)
xvek <- c(0,1)
yvek <- c(0,1)
lnx <- length(xvek)
lny <- length(yvek)
zmat <- matrix(0,lnx,lny)
# Setup the Texture coordinates - defaults seem to invert image
# tms <- matrix(c(0,0,1,1),lnx,lny) # generic case (xy-maped texture looks like png file)
# tmt <- matrix(c(0,1,0,1),lnx,lny)
tmt <- matrix(c(1,1,0,0),lnx,lny) # "correct case" (ball density look more like picture)
tms <- matrix(c(1,0,1,0),lnx,lny) # I think the gameshot.png is in error
# Texture file specified in question was stored locally in "gameshot.png"
surface3d(xvek,yvek,zmat,coord=c(3,1),texture_s=tms,texture_t=tmt,
lit=F,fog=T,color="white",textype="rgb",texture="gameshot.png",add=T)
Yields this:
I want to plot a matrix of z values with x rows and y columns as a surface similar to this graph from MATLAB.
Surface plot:
Code to generate matrix:
# Parameters
shape<-1.849241
scale<-38.87986
x<-seq(from = -241.440, to = 241.440, by = 0.240)# 2013 length
y<-seq(from = -241.440, to = 241.440, by = 0.240)
matrix_fun<-matrix(data = 0, nrow = length(x), ncol = length(y))
# Generate two dimensional travel distance probability density function
for (i in 1:length(x)) {
for (j in 1:length(y)){
dxy<-sqrt(x[i]^2+y[j]^2)
prob<-1/(scale^(shape)*gamma(shape))*dxy^(shape-1)*exp(-(dxy/scale))
matrix_fun[i,j]<-prob
}}
# Rescale 2-d pdf to sum to 1
a<-sum(matrix_fun)
matrix_scale<-matrix_fun/a
I am able to generate surface plots using a couple methods (persp(), persp3d(), surface3d()) but the colors aren't displaying the z values (the probabilities held within the matrix). The z values only seem to display as heights not as differentiated colors as in the MATLAB figure.
Example of graph code and graphs:
library(rgl)
persp3d(x=x, y=y, z=matrix_scale, color=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)))
surface3d(x=x, y=y, z=matrix_scale, color=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)))
persp(x=x, y=y, z=matrix_scale, theta=30, phi=30, col=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)), border=NA)
Image of the last graph
Any other tips to recreate the image in R would be most appreciated (i.e. legend bar, axis tick marks, etc.)
So here's a ggplot solution which seems to come a little bit closer to the MATLAB plot
# Parameters
shape<-1.849241
scale<-38.87986
x<-seq(from = -241.440, to = 241.440, by = 2.40)
y<-seq(from = -241.440, to = 241.440, by = 2.40)
df <- expand.grid(x=x,y=y)
df$dxy <- with(df,sqrt(x^2+y^2))
df$prob <- dgamma(df$dxy,shape=shape,scale=scale)
df$prob <- df$prob/sum(df$prob)
library(ggplot2)
library(colorRamps) # for matlab.like(...)
library(scales) # for labels=scientific
ggplot(df, aes(x,y))+
geom_tile(aes(fill=prob))+
scale_fill_gradientn(colours=matlab.like(10), labels=scientific)
BTW: You can generate your data frame of probabilities much more efficiently using the built-in dgamma(...) function, rather than calculating it yourself.
In line with alexis_laz's comment, here is an example using filled.contour. You might want to increase your by to 2.40 since the finer granularity increases the time it takes to generate the plot by a lot but doesn't improve quality.
filled.contour(x = x, y = y, z = matrix_scale, color = terrain.colors)
# terrain.colors is in the base grDevices package
If you want something closer to your color scheme above, you can fiddle with the rainbow function:
filled.contour(x = x, y = y, z = matrix_scale,
color = (function(n, ...) rep(rev(rainbow(n/2, ...)[1:9]), each = 3)))
Finer granularity:
filled.contour(x = x, y = y, z = matrix_scale, nlevels = 150,
color = (function(n, ...)
rev(rep(rainbow(50, start = 0, end = 0.75, ...), each = 3))[5:150]))