I'm producing an elevation map with R base function "image". Nonetheless, I'd like to get a smoother transition between levels so the image looks less pixelated. The logical solution is adding a wider color palette, which I already did, but the result isn't satisfactory yet. How can I achieve a nice smoothing effect without altering the coordinate system (I need it to overlay a series of segments and points)?
x <- 10*(1:nrow(volcano))
y <- 10*(1:ncol(volcano))
shades = colorRampPalette(c("yellow", "red"))
image(x, y, volcano,
col=shades(100),breaks=seq(min(volcano),max(volcano),
(max(volcano)- min(volcano))/100),axes = FALSE)
segments(x0=c(100,600), x1=c(600,100),
y0=c(100,600),
y1=c(600,100))
points(x=seq(100,800,100), y=rep(300,8),pch=16,col="blue",cex=3)
axis(1, at = seq(100, 800, by = 100))
axis(2, at = seq(100, 600, by = 100))
For some reason interpolate=FALSE is hard-coded in image.default, but you can use the lower-level rasterImage function directly:
m <- cut(scales::rescale(volcano), 100)
levels(m) <- shades(100)
m <- as.character(m)
dim(m) <- dim(volcano)
m <- t(m)[ncol(m):1,]
rasterImage(as.raster(m), min(x), min(y), max(x), max(y), interpolate = TRUE)
Side-by-side comparison:
Related
I have a code similar to this:
x <- rnorm(100)
y <- density(x, n = 1000)
plot(y)
polygon(y,col="red")
However, I would also like to add a colour gradient to a density plot in basic R, particularly using a palette such as the Spectral from blue to red. In this way, the output would look like this:
I appreciate any help! Thanks!
You could use segments() to add countless line segments with gradient colours.
x <- rnorm(100)
dens <- density(x, n = 1000)
plot(dens)
segments(dens$x, 0, dens$x, dens$y, col = hcl.colors(1000, "Spectral", rev = TRUE))
polygon(dens)
I want to plot a discontinuous surface using the persp function.
Here is the function:
f <- function(x, y)
{
r <- sqrt(x^2 + y^2)
out <- numeric(length(r))
ok <- r >= 1
out[ok] <- exp(-(r[ok] - 1))
return(out)
}
To get a perspective plot of the function on a regular grid, I use
x <- y <- seq(-4, 4, length.out = 50)
z <- outer(x, y, f)
persp(x, y, z, , theta = 30, phi = 30, expand = 0.5, col = "lightblue")
The resulting plot does not properly show the circular nature of discontinuity points of the surface. Any suggestion about how to obtain a better perspective plot, instead of contour plot or image?
If something interactive works for you, I would go for something like this:
library(plotly)
plot_ly(z = ~ z) %>% add_surface()
Because the circular nature is best seen from above, a phi of 90 would be best to highlight this feature, but then you lose the rest of the shape and it is pretty useless. Hence, I would go for something interactive.
persp(x, y, z, , theta = 30, phi = 30, expand = 0.5, col = "lightblue")
I would like to plot a figure similar to this example (see blow).
Here is my dataset example.
z <- data.frame(round(runif(977,500,600)))
z_matrix <- t(matrix(z[0:(as.integer(length(z[,])/10) * 10),],as.integer(length(z[,])/10),10))
I can yield some other 2D or 3D plots using ggplot, image2D, persp, and persp3d, however these plots are not looking great compared with the above 3D plot example.
I've tried using surface3d, but I got errors. I've also tried to convert the matrix format to x.y.z format using grid.to.xyz, but it seems that the format is not correct.
Furthermore, the color gradient changes with the ranges of z in various datasets. I need to "fix" a color pattern of gradient and apply it to other datasets so that they can comparable.
My questions:
how to yield a 3D plot in a matrix dataset using surface3d or plot3d?
how to fix a pattern of color gradient to a specific range of values?
Thanks for your help!
You can try with rgl surface3d for plotting your z_matrix:
library(rgl)
x <- 50*(1:nrow(z_matrix))
y <- 10*(1:ncol(z_matrix))
zlim <- range(z_matrix)
zlen <- zlim[2] - zlim[1] + 1
colorlut <- rainbow(zlen) # height color lookup table
col <- colorlut[ z_matrix - zlim[1] + 1 ] # assign colors to heights for each point
open3d()
surface3d(x, y, z_matrix, color = col, back = "lines")
With grid lines (and without scaling x,y axes):
x <- 1:nrow(z_matrix)
y <- 1:ncol(z_matrix)
zlim <- range(z_matrix)
zlen <- zlim[2] - zlim[1] + 1
colorlut <- terrain.colors(zlen) #rainbow(zlen) # height color lookup table
col <- colorlut[ z_matrix - zlim[1] + 1 ] # assign colors to heights for each point
open3d()
persp3d(x, y, z_matrix, col = col)
grid3d(c("x", "y+", "z"))
surface3d(x, y, z_matrix, color = col, back = "lines")
Following my own advice and using the volcano dataset, this is what I thought was the best match to your desired image as far as the background:
library(plot3d)
persp3D(z = volcano, col = "lightblue", shade = 0.5,
ticktype = "detailed", bty = "b2")
And this would be the coloring scheme best fit in the worked examples, but I think you might want to search on "terrain colors" if you needed an more exact fit to that image:
png(); persp3D(z = volcano, clab = c("height", "m"),
colkey = list(length = 0.5, shift = -0.1),
ticktype = "detailed", bty = "b2"); dev.off()
That package is using base graphics, so you would want to review the rotation options by reading the ?persp and ?persp3D help pages. Here's another experiment:
png(); persp3D(z = volcano, col=terrain.colors(100), clab = c("height", "m"), xlab="PPM" , ylab="Col", zlab="Height",
colkey=FALSE, theta=25, lighting="specular",
ticktype = "detailed", bty = "b2"); dev.off()
I am producing a color density scatterplot in R using the smoothScatter() function.
Example:
## A largish data set
n <- 10000
x1 <- matrix(rnorm(n), ncol = 2)
x2 <- matrix(rnorm(n, mean = 3, sd = 1.5), ncol = 2)
x <- rbind(x1, x2)
oldpar <- par(mfrow = c(2, 2))
smoothScatter(x, nrpoints = 0)
Output:
The issue I am having is that I am unsure how to add a legend/color scale that describes the relative difference in numeric terms between different shades. For example, there is no way to tell whether the darkest blue in the figure above is 2 times, 10 times or 100 times as dense as the lightest blue without some sort of legend or color scale. Is there any way in R to retrieve the requisite information to make such a scale, or anything built in that can produce a color scale of this nature automatically?
Here is an answer that relies on fields::imageplot and some fiddling with par(mar) to get the margins correct
fudgeit <- function(){
xm <- get('xm', envir = parent.frame(1))
ym <- get('ym', envir = parent.frame(1))
z <- get('dens', envir = parent.frame(1))
colramp <- get('colramp', parent.frame(1))
fields::image.plot(xm,ym,z, col = colramp(256), legend.only = T, add =F)
}
par(mar = c(5,4,4,5) + .1)
smoothScatter(x, nrpoints = 0, postPlotHook = fudgeit)
You can fiddle around with image.plot to get what you want and look at ?bkde2D and the transformation argument to smoothScatter to get an idea of what the colours represent.
I am producing a color density scatterplot in R using the smoothScatter() function.
Example:
## A largish data set
n <- 10000
x1 <- matrix(rnorm(n), ncol = 2)
x2 <- matrix(rnorm(n, mean = 3, sd = 1.5), ncol = 2)
x <- rbind(x1, x2)
oldpar <- par(mfrow = c(2, 2))
smoothScatter(x, nrpoints = 0)
Output:
The issue I am having is that I am unsure how to add a legend/color scale that describes the relative difference in numeric terms between different shades. For example, there is no way to tell whether the darkest blue in the figure above is 2 times, 10 times or 100 times as dense as the lightest blue without some sort of legend or color scale. Is there any way in R to retrieve the requisite information to make such a scale, or anything built in that can produce a color scale of this nature automatically?
Here is an answer that relies on fields::imageplot and some fiddling with par(mar) to get the margins correct
fudgeit <- function(){
xm <- get('xm', envir = parent.frame(1))
ym <- get('ym', envir = parent.frame(1))
z <- get('dens', envir = parent.frame(1))
colramp <- get('colramp', parent.frame(1))
fields::image.plot(xm,ym,z, col = colramp(256), legend.only = T, add =F)
}
par(mar = c(5,4,4,5) + .1)
smoothScatter(x, nrpoints = 0, postPlotHook = fudgeit)
You can fiddle around with image.plot to get what you want and look at ?bkde2D and the transformation argument to smoothScatter to get an idea of what the colours represent.