R: Point colours determined by X, Y and Z values with scatterplot3d - r

I have this R script that uses scatterplot3d:
library(scatterplot3d)
attach(mtcars)
rgb <- read.csv(file="rgb-data.csv",head=TRUE,sep=",")
scatterplot3d(rgb$R,rgb$G,rgb$B,
xlim=c(0,255), ylim=c(0,255),zlim=c(0,255),
xlab="R", ylab="G", zlab="B", pch=".",
main=paste("Feature Space"))
Sample data for rgb-data.csv is:
R,G,B
12,48,126
127,12,48
46,127,12
It produces the plot:
I'm looking for 4 changes:
Have the (0,0,0) point being the front most point in the cube, most central, rather than the point in the bottom left of the plot. Is this possible?
Have the colour of each point reflect the R, G and B values of each point. E.g. (12,48,126) in the above dataset, the R value of the point is 12, G is 48 and B is 126. Is this possible?
The X, Y and Z axis range from 0 to 255 in the R script. However, in the plot they range from 0 to 300. I'd like the axis ranges to be 0 to 255 in the generated plot. Is this possible?
The "B" and "G" axis labels are rotated 270 degrees. I'd like them the same orientation as the "R" axis label. Is this possible?

I am not sure if I understood the 1st question correctly. But, here's the code.
Control with xlim, ylim, zlim
Use RGB function (note that you probably need to change your variable name since the function is called rgb)
Control with x.ticklabs, y.ticklabs, z.ticklabs
The code
library(scatterplot3d)
R <- sample(0:255, 100)
G <- sample(0:255, 100)
B <- sample(0:255, 100)
RGB_ <- rgb(R/255, G/255, B/255)
r_ticks <- c(-255, -200, -100, 0, 100, 200, 255)
ticks <- c(0, 50, 100, 150, 200, 250, 255)
scatterplot3d(R, G, B,
xlim=c(-255, 255),
ylim=c(0, 255),
zlim=c(0, 255),
color=RGB_,
x.ticklabs=r_ticks,
y.ticklabs=ticks,
z.ticklabs=ticks)

Have the (0,0,0) point being the front most point in the cube, most central, rather than the point in the bottom left of the plot. Is this possible?
Setting angle=140 in scatterplot3d( ) provided something close the desired plot:
The (0,0,0) position is more central at the bottom of the plot. I was also envisaging the R and G axes to be sloped slightly upwards into the distance from 0 to 255.
Have the colour of each point reflect the R, G and B values of each point. E.g. (12,48,126) in the above dataset, the R value of the point is 12, G is 48 and B is 126. Is this possible?
Based on Mo K's answer, adding
color=rgb(dat$R, dat$G, dat$B, maxColorValue = 255)
to scatterplot3d( ) gives the desired effect, provided renaming the original variable to dat i.e.
dat <- read.csv(file="rgb-data.csv",head=TRUE,sep=",")
The X, Y and Z axis range from 0 to 255 in the R script. However, in the plot they range from 0 to 300. I'd like the axis ranges to be 0 to 255 in the generated plot. Is this possible?
Mo K's answer works. Adding
ticks <- c(0, 50, 100, 150, 200, 250, 255)
Then
x.ticklabs=ticks,
y.ticklabs=ticks,
z.ticklabs=ticks
to scatterplots3d( ).
The "B" and "G" axis labels are rotated 270 degrees. I'd like them the same orientation as the "R" axis label. Is this possible?
I haven't found a solution to this yet.

Related

How to change Scale in raster plot?

Complete R noob, need help plotting a raster with a good scale.
rast <- raster("accessibility.tif")
pal <- colorRampPalette(c("green","red"))
plot(rast,
col = pal(10),
zlim = c(0,180))
This is what the output is:
See, all the values after 180 are simply not plot.
It's like they're cut out of the scale.
This wont do as there are a good minority of values after 180 that go till 3500.
I don't want the scale to go from 0 - 180,
I need it to go from 0 - 180+
I want all of those points to be plot in Red too.
Thank You for your help
You can do something like this:
library(raster)
rast <- raster("accessibility.tif")
r <- clamp(rast, 0, 180)
pal <- colorRampPalette(c("green","red"))
plot(r, col = pal(10))

R rgl 3d log scale plot and Antenna pattern plots

first of all before my sharing my problem I want to share a bit of code that might be helpful for some people outside there. I have been looking quite some time code to plot in 3d antenna measurements but I could not find code that does that. The problem is that antenna measurements have polar coordinates and typical 3d plot functions use cartesian coordinates. So my code below does just that (I am not an advanced programmer so I am sure someone might be able to optimize it for its use). The code can be run directly and I added comments to make it easier readable.
require("rgl")
require("fields")
degreeToRadian<-function(degree){
return (0.01745329252*degree)
}
turnPolarToX<-function(Amplitude,Coordinate){
return (Amplitude*cos(degreeToRadian(Coordinate)))
}
turnPolarToY<-function(Amplitude,Coordinate){
return (Amplitude*sin(degreeToRadian(Coordinate)))
}
# inputs for the code
test<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
test2<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
test3<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
# My three input vectors above are considered to be dBm values, typically unit for antenna or propagation measurements
# I want to plot those on three different 3d planes the XY, the YZ and the ZX. Since the rgl does not support
# polar coordinates I need to cast my polar coordinates to cartesian ones, using the three functions
# defined at the beginning. I also need to change my dBm values to their linear relative ones that are the mW
# Convert my dBm to linear ones
test<-10^(test/10)
test2<-10^(test2/10)
test3<-10^(test3/10)
# Start preparing the data to be plotted in cartesian domain
X1<-turnPolarToX(test,1:359)
Y1<-turnPolarToY(test,1:359)
Z1<-rep(0,359)
X2<-turnPolarToX(test2,1:359)
Y2<-rep(0,359)
Z2<-turnPolarToY(test2,1:359)
X3<-rep(0,359)
Y3<-turnPolarToX(test3,1:359)
Z3<-turnPolarToY(test3,1:359)
# Time for the plotting now
Min<-min(test,test2,test3)
Max<-max(test,test2,test3)
bgplot3d( suppressWarnings (
image.plot( legend.only=TRUE, legend.args=list(text='dBm/100kHz'), zlim=c(Min,Max),col=plotrix::color.scale(seq(Min,Max,length.out=21),c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)))
) # zlim is the colorbar numbers
)
# for below alternatively you can also use the lines3d to get values
points3d(X1,Y1,Z1,col=plotrix::color.scale(test,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
points3d(X2,Y2,Z2,col=plotrix::color.scale(test2,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
points3d(X3,Y3,Z3,col=plotrix::color.scale(test3,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
The problem I have now is that my plotting ideally I would like to be on a log scale that the rgl packet does not support! If I try to use log on my X,Y,Z to compress them I get an error that log is not defined for negative numbers (of course that is correct). How would you think to solve that problem on compressing the axes values when log scale plotting is not supported?
I would like to thank you for your reply
Regards
Alex
It doesn't make sense to apply a log scale to X, Y and Z. Just apply it to your original data, and transform the logged values to polar coordinates.
Since your logged test values are negative, you probably will want to apply an offset; polar coordinates with negative radius values are pretty hard to interpret.
Once you have done that, you can use the axis3d() function to add an axis with arbitrary labels to the plot. For example, if you want the origin to correspond to -50 dBm, you'd skip the transformation to linear coordinates and just add 50. You need to undo this when calculating labels. Here's your example, modified:
require("rgl")
require("fields")
degreeToRadian<-function(degree){
return (0.01745329252*degree)
}
turnPolarToX<-function(Amplitude,Coordinate){
return (Amplitude*cos(degreeToRadian(Coordinate)))
}
turnPolarToY<-function(Amplitude,Coordinate){
return (Amplitude*sin(degreeToRadian(Coordinate)))
}
# inputs for the code
test<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
test2<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
test3<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
# Add an offset of 50 to the values.
test <- test + 50
test2 <- test2 + 50
test3 <- test3 + 50
# Start preparing the data to be plotted in cartesian domain
X1<-turnPolarToX(test,1:359)
Y1<-turnPolarToY(test,1:359)
Z1<-rep(0,359)
X2<-turnPolarToX(test2,1:359)
Y2<-rep(0,359)
Z2<-turnPolarToY(test2,1:359)
X3<-rep(0,359)
Y3<-turnPolarToX(test3,1:359)
Z3<-turnPolarToY(test3,1:359)
# Time for the plotting now
Min<-min(test,test2,test3)
Max<-max(test,test2,test3)
bgplot3d( suppressWarnings (
image.plot( legend.only=TRUE, legend.args=list(text='dBm/100kHz'), zlim=c(Min,Max)-50,col=plotrix::color.scale(seq(Min-50,Max-50,length.out=21),c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)-50))
) # zlim is the colorbar numbers
)
# for below alternatively you can also use the lines3d to get values
points3d(X1,Y1,Z1,col=plotrix::color.scale(test,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
points3d(X2,Y2,Z2,col=plotrix::color.scale(test2,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
points3d(X3,Y3,Z3,col=plotrix::color.scale(test3,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
# Add axes
labels <- pretty(c(-50, -20))
axis3d("x", at = labels + 50, labels = labels, pos = c(NA, 0, 0) )
axis3d("y", at = labels + 50, labels = labels, pos = c(0, NA, 0) )
axis3d("z", at = labels + 50, labels = labels, pos = c(0, 0, NA) )
One my system it produces this display:
You might want to add circles to show how the scale continues around in each plane. This code would do it:
theta <- seq(0, 2*pi, len = 100)
for (i in seq_along(labels)) {
x <- (labels[i] + 50)*cos(theta)
y <- (labels[i] + 50)*sin(theta)
lines3d(x, y, 0)
lines3d(x, 0, y)
lines3d(0, x, y)
}
I find the plot too busy with those added, but you can try it and decide for yourself.

Wrong axes in raster converted from matrix

I have following code:
library(raster)
library(rasterVis)
library(rgl)
mz <- matrix(5:7, 2040, 10000)
z <- raster(mz, xmn=0, ymn=0, xmx=ncol(mz)-1, ymx=nrow(mz)-1)
plot3D(z)
decorate3d()
This creates following image
As you can see y axis goes from 0 to 12 instead of 0 to 2040. And X axis goes up to 60, instead of 10000.
What shall I do to get the real values on the axis?
And how do I enforce showing 0 on the Z axis?
This result is documented in the examples of the help page of plot3D:
Default: x-axis and y-axis are adjusted with z-values. Therefore,
labels with decorate3d() are useless [...] Set adjust=FALSE to fix it
plot3D(z, adjust=FALSE)
decorate3d()

Fill under line curve

For the sample dataset below, I would like to just plot the y as a smooth line with fill under the line using R.
I am able to get smooth line but not the color filled curve. Could someone please help me here?
date, y
2015-03-11, 71.12
2015-03-10, 34.0
2015-03-09, 11.1
2015-03-08, 9.62
2015-03-07, 25.97
2015-03-06, 49.7
2015-03-05, 38.05
2015-03-04, 38.05
2015-03-03, 29.75
2015-03-02, 35.85
2015-03-01, 30.65
The code I used to plot the smooth line is as follows. I am unable to get fill the portion under the line with a color
y <- df$y
x <- 1:length(y)
plot(x, y, type='n')
smooth = smooth.spline(x, y, spar=0.5)
lines(smooth)
EDIT
Using the polygon function does not give what is expected. The shaded area should be below the line not above
with(smooth, polygon(x, y, col="gray"))
Describe a polygon by listing its boundary vertices in order as you march around it.
This polygon's boundary consists of the curve plus two more vertices at the bottom right and bottom left. To help you see them, I have overplotted the vertices, varying their colors by position in the sequence.
Here is the R code that did it. It used predict to obtain coordinates of the curve from the spline object, then adjoined the x- and y-coordinates of the two extra points using the concatenation operator c. To make the filling go to the axis, the plot range was manually set.
y <- c(71, 34, 11, 9.6, 26, 50, 38, 38, 30, 36, 31)
n <- length(y)
x <- 1:n
s = smooth.spline(x, y, spar=0.5)
xy <- predict(s, seq(min(x), max(x), by=1)) # Some vertices on the curve
m <- length(xy$x)
x.poly <- c(xy$x, xy$x[m], xy$x[1]) # Adjoin two x-coordinates
y.poly <- c(xy$y, 0, 0) # .. and the corresponding y-coordinates
plot(range(x), c(0, max(y)), type='n', xlab="X", ylab="Y")
polygon(x.poly, y.poly, col=gray(0.95), border=NA) # Show the polygon fill only
lines(s)
points(x.poly, y.poly, pch=16, col=rainbow(length(x.poly))) # (Optional)

R: 3D surface plot (persp3d) with fixed coordinates like in Excel

I have my R data in x, y, and z format, x and y being vectors of length 10 and 19 respectively and z being a matrix of 10x19 integers. I have the following code that prints my 3D surface:
height <- (z - range(z)[1]) / diff(range(z))
r.prop <- height
g.prop <- 0
b.prop <- 1 - height
color <- rgb(r.prop, g.prop, b.prop, maxColorValue=1)
persp3d(x, y, z, theta=50, phi=25, expand=0.75, col=color, ticktype="detailed",
xlab="filesize [kb]", ylab="record size [kb]", zlab="speed [b/s]",
axes=TRUE)
My problem is that the y axis contains powers of 2 (4, 8, 16, 32, 64, ..., 2048,..), which squeezes most of my data points into the low-range part of the plot. What I want is an even distribution of the data points, i.e. between point 4 and 8 should be the same space as between 1024 and 2048 just like it is in the Excel spreadsheet surface plot.
Can you tell me which command or parameter would make that happen with persp3d?
Thanks a bunch!
Loddi
Addition:
After changing the the axes to log2, or just doing a c(1:length(x)) and c(1:length(y)) instead of the actual axis values, it looks better but now has these weird jigsaw shape that is not at all represented in my data. Do you guys have a clue what is going on here?
see picture here http://i.stack.imgur.com/WBI3r.png
Try log2(y) instead of y
persp3d(x, log2(y), z, theta=50, phi=25, expand=0.75, col=color, ticktype="detailed",
xlab="filesize [kb]", ylab="record size [kb]", zlab="speed [b/s]", axes=FALSE,
normal_x=x, normal_y=y, normal_z=z)

Resources