I have the following data in a data frame:
**x** in (0,1)
**y** in [0,1]
**z** in [0,1]
For example:
X,Y,Z
0.1, 0.2, 0.56
0.1, 0.3, 0.57
...
I'd like to plot them on this type of chart:
I tried on R, but all I could get was a not-so-fancy 3d scatterplot.
I also read about the lattice 3d wireframe, but I couldn't get my head around it.
What am I supposed to do to get a Matlab like wireframe in R?
What data transforms are involved?
This is the sample code from the documentation:
x <- seq(-pi, pi, len = 20)
y <- seq(-pi, pi, len = 20)
g <- expand.grid(x = x, y = y)
g$z <- sin(sqrt(g$x^2 + g$y^2))
wireframe(z ~ x * y, g, drape = TRUE,
aspect = c(3,1), colorkey = TRUE)
I don't find it particularly clear.
EDIT: the persp3d function works fine, and I was able to generate a 3d plot with one colour. How can I set a colour scale relative to the z value?
Thanks for any hints,
Mulone
Use outer to create the z values and then use persp to plot:
z <- outer(x,y, function(x,y) sin(sqrt(x^2+y^2)))
persp(x,y,z)
There are options for colouring and setting the viewing angle, see ?persp. See the fourth example for Matlab style colouring.
For an interactive plot, consider using persp3d in the rgl package:
require(rgl)
persp3d(x,y,z,col="blue")
Edit
To add colour, there is a slight difference from the method in persp, since the colour relates to the vertex rather than the centre of the facet, but it makes it easier.
jet.colors <- colorRampPalette( c("blue", "green") )
pal <- jet.colors(100)
col.ind <- cut(z,100) # colour indices of each point
persp3d(x,y,z,col=pal[col.ind])
The help file recommends adding the parameter smooth=FALSE, but that's down to personal preference.
Related
I am plotting the density of a two-dimensional, weighted spatial point pattern. I'd like to make the plot without a colour scale legend, and save it with no (or minimal) boarders on all sides, like this: My problem is that I can't remove the colour scale legend. Reproducible code below:
## Install libraries:
library(spatstat) #spatial package
library(RColorBrewer) #create custom colour ramps
## Create reproducible data:
data <- data.frame(matrix(ncol = 3, nrow = 50))
x <- c("x", "y", "weight")
colnames(data) <- x
data$x <- runif(50, 0, 20)
data$y <- runif(50, 0, 20)
data$weight <- sample(1:200, 50)
## Set plotting window and colours:
plot.win <- owin(c(0,20), c(0,20)) # plot window as 20x20m
spat.bat.frame <- NULL # create a frame to store values in
cols1<-colorRampPalette(brewer.pal(9,"Blues"))(100) #define colour ramp for density plots
## Create and save plots:
jpeg(filename = "Bad plot.jpeg", res = 300, units = "cm", width = 20, height = 20)
par(mar=c(0,0,0,0),oma=c(0,0,0,0),lwd=1)
ppp_01 <- ppp(x = data$x, y = data$y, window = plot.win)
ppp_02 <- ppp(x = data$x, y = data$y, window = plot.win)
plot(density(ppp_01, weights = data$weights), main=NULL, col=cols1, sigma = 1)
plot(ppp_02, add=TRUE) #add spp points to density plot
dev.off()
I've tried legend=FALSE, auto.key=FALSE, colorkey=FALSE, which don't seem to be compatible with plot() (i.e. they don't give an error but don't change anything). I've also tried some work-arounds like saving a cropped image with dev.off.crop() or by adjusting margins with par(), but haven't been able to completely remove the legend. Does anyone have any suggestions on how to remove a colour scale legend of a density spp (real-valued pixel image) using plot()?
I specifically need to plot the density of the spatial point pattern, to specify a custom colour ramp, and to overlay the spp points onto the density image. I could try plotting with spplot() instead, but I'm not sure this will allow for these three things, and I feel like I'm missing a simple fix with plot(). I can't crop the figures manually after saving from R because there are 800 of them, and I need them all to be exactly the same size and in the exact same position.
Thank you!
Since plot is a generic function, the options available for controlling the plot will depend on the class of object that is being plotted. You want to plot the result of density(ppp_01, weights = data$weights). Let's call this Z:
Z <- density(ppp_01, weights = data$weights, sigma=1)
Note: the smoothing bandwidth sigma should be given inside the call to density
To find out about Z, you can just print it, or type class(Z).
The result is that Z is an object of class"im" (pixel image).
So you need to look up the help file for plot.im, the plot method for class "im". Typing ?plot.im shows that there is an argument ribbon that controls whether or not the colour ribbon is displayed. Simply set ribbon=FALSE in the call to plot:
plot(Z, ribbon=FALSE, main="", col=cols1)
Or in your original code
plot(density(ppp_01, weights=data$weights, sigma=1), main="", col=cols1)
However I strongly recommend separating this into two lines, one which creates the image object, and one which plots the image. This makes it much easier to spot mistakes like the misplacement of the sigma argument.
I have a perspective plot of a locfit model and I wish to add two things to it
Predictor variables as points in the 3D space
Color the surface according to the Z axis value
For the first, I have tried to use the trans3d function. But I get the following error even though my variables are in vector format:
Error in cbind(x, y, z, 1) %*% pmat : requires numeric/complex matrix/vector arguments
Here is a snippet of my code
library(locfit)
X <- as.matrix(loc1[,1:2])
Y <- as.matrix(loc1[,3])
zz <- locfit(Y~X,kern="bisq")
pmat <- plot(zz,type="persp",zlab="Amount",xlab="",ylab="",main="Plains",
phi = 30, theta = 30, ticktype="detailed")
x1 <- as.vector(X[,1])
x2 <- as.vector(X[,2])
Y <- as.vector(Y)
points(trans3d(x1,x2,Y,pmat))
My "loc1" data can be found here - https://www.dropbox.com/s/0kdpd5hxsywnvu2/loc1_amountfreq.txt?dl=0
TL,DR: not really in plot.locfit, but you can reconstruct it.
I don't think plot.locfit has good support for this sort of customisation. Supposedly get.data=T in your plot call will plot the original data points (point 1), and it does seem to do so, except if type="persp". So no luck there. Alternatively you can points(trans3d(...)) as you have done, except you need the perspective matrix returned by persp, and plot.locfit.3d does not return it. So again, no luck.
For colouring, typically you make a colour scale (http://r.789695.n4.nabble.com/colour-by-z-value-persp-in-raster-package-td4428254.html) and assign each z facet the colour that goes with it. However, you need the z-values of the surface (not the z-values of your original data) for this, and plot.locfit does not appear to return this either.
So to do what you want, you'll essentially be recoding plot.locfit yourself (not hard, though just cludgy).
You could put this into a function so you can reuse it.
We:
make a uniform grid of x-y points
calculate the value of the fit at each point
use these to draw the surface (with a colour scale), saving the perspective matrix so that we can
plot your original data
so:
# make a grid of x and y coords, calculate the fit at those points
n.x <- 20 # number of x points in the x-y grid
n.y <- 30 # number of y points in the x-y grid
zz <- locfit(Total ~ Mex_Freq + Cal_Freq, data=loc1, kern="bisq")
xs <- with(loc1, seq(min(Mex_Freq), max(Mex_Freq), length.out=20))
ys <- with(loc1, seq(min(Cal_Freq), max(Cal_Freq), length.out=30))
xys <- expand.grid(Mex_Freq=xs, Cal_Freq=ys)
zs <- matrix(predict(zz, xys), nrow=length(xs))
# generate a colour scale
n.cols <- 100 # number of colours
palette <- colorRampPalette(c('blue', 'green'))(n.cols) # from blue to green
# palette <- colorRampPalette(c(rgb(0,0,1,.8), rgb(0,1,0,.8)), alpha=T)(n.cols) # if you want transparency for example
# work out which colour each z-value should be in by splitting it
# up into n.cols bins
facetcol <- cut(zs, n.cols)
# draw surface, with colours (col=...)
pmat <- persp(x=xs, y=ys, zs, theta=30, phi=30, ticktype='detailed', main="plains", xlab="", ylab="", zlab="Amount", col=palette[facetcol])
# draw your original data
with(loc1, points(trans3d(Mex_Freq,Cal_Freq,Total,pmat), pch=20))
Note - doesn't look that pretty! might want to adjust say your colour scale colours, or the transparency of the facets, etc. Re: adding legend, there are some other questions that deal with that.
(PS: what a shame ggplot doesn't do 3D scatter plots.)
Suppose that (x(t),y(t)) has polar coordinates(√t,2πt). Plot (x(t),y(t)) for t∈[0,10].
There is no proper function in R to plot with polar coordinates. I tried normal plot by giving, x=√t & y=2πt.
But resultant graph was not as expected.
I got this question from "Introduction to Scientific Programming and Simulation using r"and the book is telling the plot should be spiral.
Make a sequence:
t <- seq(0,10, len=100) # the parametric index
# Then convert ( sqrt(t), 2*pi*t ) to rectilinear coordinates
x = sqrt(t)* cos(2*pi*t)
y = sqrt(t)* sin(2*pi*t)
png("plot1.png");plot(x,y);dev.off()
That doesn't display the sequential character, so add lines to connect adjacent points in the sequence:
png("plot2.png");plot(x,y, type="b");dev.off()
As already mentioned in a previous comment, R can plot using polar coordinates. The package plotrix has a function called polar.plot that does this. Polar coordinates are defined by length and angle. This function can take a sequence of lengths and a sequence of angles to plot with polar coordinates. For example to make one spiral:
library(plotrix)
plt.lns <- seq(1, 100, length=500)
angles <- seq(0, 5*360, length=500)%%360
polar.plot(plt.lns, polar.pos=angles, labels="", rp.type = "polygon")
An option worth a try, It is Plotly package.
library(plotly)
p <- plot_ly(plotly::mic, r = ~r, t = ~t, color = ~nms, alpha = 0.5, type = "scatter")
layout(p, title = "Mic Patterns", orientation = -90)
Note: If you are using RStudio, the plots are going to be shown in Viewer tab.
Is it possible to plot the SOM map (package Kohonen) with hexagons
as elementary forms instead of circles? Now the different plottings
(count, changes etc.) are plotted as circles with white surroundings.
The aim is to create SOM visuals similar to Matlab SOM Toolbox.
This discussion suggests hexagon plotting would not have been possible 2010.
Even though there is already an answer, perhaps this different method will be a good addition. With the code you can create a heatmap similar to the one below
I took this piece of code from a more extensive program I wrote around the kohonen package. You can find my full explanation of the program here: http://nbremer.blogspot.nl/2013/07/on-creation-of-extended-self-organizing.html
It is a bit coding and you need to start with a specific kind of variable: the input <<Heatmap matrix variable>> is a matrix that would be the numerical representation of you heatmap.
Here [1,1] will become the lower left node (1st row, 1st column), [1,2] will become the node to the right, [2,1] will be the first node to the left in the second row, etc.
So visually you work your way from bottom left to top right in the Heatmap, while in the matrix you work from top left to bottom right
library(RColorBrewer) #to use brewer.pal
library(fields) #to use designer.colors
#Function to create the polygon for each hexagon
Hexagon <- function (x, y, unitcell = 1, col = col) {
polygon(c(x, x, x + unitcell/2, x + unitcell, x + unitcell,
x + unitcell/2), c(y + unitcell * 0.125, y + unitcell *
0.875, y + unitcell * 1.125, y + unitcell * 0.875,
y + unitcell * 0.125, y - unitcell * 0.125),
col = col, border=NA)
}#function
#Start with a matrix that would be the numerical representation of you heatmap
#Here [1,1] will become the lower left node (1st row, 1st column),
#[1,2] will become the node to the right
#[2,1] will be the first node to the left in the second row
#So visually you work your way from bottom left to top right
x <- as.vector(<<Heatmap matrix variable>>)
#Number of rows and columns of your SOM
SOM_Rows <- dim(<<Heatmap matrix variable>>)[1]
SOM_Columns <- dim(<<Heatmap matrix variable>>)[2]
#To make room for the legend
par(mar = c(0.4, 2, 2, 7))
#Initiate the plot window but do show any axes or points on the plot
plot(0, 0, type = "n", axes = FALSE, xlim=c(0, SOM_Columns),
ylim=c(0, SOM_Rows), xlab="", ylab= "", asp=1)
#Create the color palette
#I use designer.colors to interpolate 50 colors between
#the maxmimum number of allowed values in Brewer
ColRamp <- rev(designer.colors(n=50, col=brewer.pal(9, "Spectral")))
#Make a vector with length(ColRamp) number of bins between the minimum and
#maximum value of x.
#Next match each point from x with one of the colors in ColorRamp
ColorCode <- rep("#FFFFFF", length(x)) #default is all white
Bins <- seq(min(x, na.rm=T), max(x, na.rm=T), length=length(ColRamp))
for (i in 1:length(x))
if (!is.na(x[i])) ColorCode[i] <- ColRamp[which.min(abs(Bins-x[i]))]
#Actual plotting of hexagonal polygons on map
offset <- 0.5 #offset for the hexagons when moving up a row
for (row in 1:SOM_Rows) {
for (column in 0:(SOM_Columns - 1))
Hexagon(column + offset, row - 1, col = ColorCode[row + SOM_Rows * column])
offset <- ifelse(offset, 0, 0.5)
}
#Add legend to the right if you want to
image.plot(legend.only=TRUE, col=ColRamp, zlim=c(min(x, na.rm=T), max(x, na.rm=T)))
I don't have sufficient reputation to comment on #NBremer's answer. I have extended the above code to allow visualization of large component planes and u-matrices for output from the R "kohonen" library. Code and worked examples available here:
R SOM Visualization Functions
You can use Voronoi plots to get a space filled representation (hexagons).
the hex grid coordinates are stored in $grid$pts of the kohonen object,
the codes are in $codes
Putting this together with a lattice plot:
require ("kohonen")
require ("latticeExtra")
require ("deldir")
som.wines <- som (scale (wines), grid = somgrid(5, 5, "hexagonal"))
df <- as.data.frame (cbind (som.wines$grid$pts, som.wines$codes))
levelplot (alcohol ~ x * y, data = df, panel = panel.voronoi, aspect = "iso)
yields:
(I don't know for sure, but I guess that would have been possible already in 2010).
I would like to have a plot in R similar to the 2D smoothScatter plot, but with an extra dimension using something like a palette of different colours or a surface. Is this possible with any package?
Example:
x = rnorm(1000)
y = rnorm(1000,10)
z = rnorm(1000,5)
smoothScatter(x,y)
somemagicmethod(x,y,z)
library(fields)
library(akima)
s <- interp(x,y,z)
image.plot(s)