I have been playing around with the MASS package and can plot the two bivariate normal simply using image and par(new=TRUE) for example:
# lets first simulate a bivariate normal sample
library(MASS)
bivn <- mvrnorm(1000, mu = c(0, 0), Sigma = matrix(c(1, .5, .5, 1), 2))
bivn2 <- mvrnorm(1000, mu = c(0, 0), Sigma = matrix(c(1.5, 1.5, 1.5, 1.5), 2))
# now we do a kernel density estimate
bivn.kde <- kde2d(bivn[,1], bivn[,2], n = 50)
bivn.kde2 <- kde2d(bivn2[,1], bivn[,2], n = 50)
# fancy perspective
persp(bivn.kde, phi = 45, theta = 30, shade = .1, border = NA)
par(new=TRUE)
persp(bivn.kde2, phi = 45, theta = 30, shade = .1, border = NA)
Which doesn't look very good, I guess I have to just play around with the axis and stuff.
But if I try a similar approach with the contour the plots do not overlap. They are simply replaced:
# fancy contour with image
image(bivn.kde); contour(bivn.kde, add = T)
par(new=TRUE)
image(bivn.kde2); contour(bivn.kde, add = T)
Is this the best approach to what I want or am I just making it hard on myself? Any suggestions are welcome. Thank you!
Perhaps you can use rgl library. It allows you to create interactive 3d plots.
require(rgl)
col1 <- rainbow(length(bivn.kde$z))[rank(bivn.kde$z)]
col2 <- heat.colors(length(bivn.kde2$z))[rank(bivn.kde2$z)]
persp3d(x=bivn.kde, col = col1)
with(bivn.kde2, surface3d(x,y,z, color = col2))
If you want to plot difference between two surfaces then you can do something like below.
res <- list(x = bivn.kde$x, y = bivn.kde$y, z = bivn.kde$z - bivn.kde2$z)
col3 <- heat.colors(length(res$z))[rank(res$z)]
persp3d(res, col = col3)
Related
I am plotting a count histogram of my data and then overlaying the shape of the gamma distribution that I think underlies the data. The points on the gamma distribution are generated using dgamma and plotted using curve. No matter how many points I use to generate the curve, the output still looks pixellated. Does anyone know why and is it possible to obtain a smooth curve?
dt <- rgamma(100, shape = 2.59, scale = 0.16)
n <- 1000
x <- seq(min(dt), max(dt), length.out = n)
hist(dt, freq = FALSE, ylim = c(0, 2.5), xlab = "D")
curve(dgamma(x, shape = 2.59, scale = 0.16), add = TRUE, lwd = 2, n = n)
curve has a n attribute that defaults to 101 you need to increase that. So note that not the datapoints you throw in determine your resolution.
curve(dgamma(x, shape = 2.59, scale = 0.16), add = TRUE, lwd = 2, n = n) # then it takes your defined n = 1000
I would like to generate a 3d scatterplot that includes volumes around groups of points. Something like this, but in R.
These could be rough spheroids or something more complex like in the image linked above, honestly I'm just trying to illustrate hypervolume overlap for a presentation. It seems like I could build a kernel density estimation for each set of points and plot that, but I can't figure out how to do so.
The scatterplot that I am using as a base is very similar to that generated by this code:
# Code from http://www.sthda.com/english/wiki/impressive-package-for-3d-and-4d-graph-r-software-and-data-visualization#change-the-color-by-groups
library(plot3D)
# Set up data
data(iris)
x <- sep.l <- iris$Sepal.Length
y <- pet.l <- iris$Petal.Length
z <- sep.w <- iris$Sepal.Width
# Make 3d scatterplot with colors by category
scatter3D(x, y, z, bty = "g", pch = 18,
col.var = as.integer(iris$Species),
col = c("#1B9E77", "#D95F02", "#7570B3"),
pch = 18, ticktype = "detailed",
colkey = list(at = c(2, 3, 4), side = 1,
addlines = TRUE, length = 0.5, width = 0.5,
labels = c("setosa", "versicolor", "virginica")) )
Bonus: If you can tell me how to edit the hypervolume() package so that plotting a hypervolume object works properly you would have my undying gratitude. See here for better description of the problems.
I have been playing around with the MASS package and can plot the two bivariate normal simply using image and par(new=TRUE) for example:
# lets first simulate a bivariate normal sample
library(MASS)
bivn <- mvrnorm(1000, mu = c(0, 0), Sigma = matrix(c(1, .5, .5, 1), 2))
bivn2 <- mvrnorm(1000, mu = c(0, 0), Sigma = matrix(c(1.5, 1.5, 1.5, 1.5), 2))
# now we do a kernel density estimate
bivn.kde <- kde2d(bivn[,1], bivn[,2], n = 50)
bivn.kde2 <- kde2d(bivn2[,1], bivn[,2], n = 50)
# fancy perspective
persp(bivn.kde, phi = 45, theta = 30, shade = .1, border = NA)
par(new=TRUE)
persp(bivn.kde2, phi = 45, theta = 30, shade = .1, border = NA)
Which doesn't look very good, I guess I have to just play around with the axis and stuff.
But if I try a similar approach with the contour the plots do not overlap. They are simply replaced:
# fancy contour with image
image(bivn.kde); contour(bivn.kde, add = T)
par(new=TRUE)
image(bivn.kde2); contour(bivn.kde, add = T)
Is this the best approach to what I want or am I just making it hard on myself? Any suggestions are welcome. Thank you!
Perhaps you can use rgl library. It allows you to create interactive 3d plots.
require(rgl)
col1 <- rainbow(length(bivn.kde$z))[rank(bivn.kde$z)]
col2 <- heat.colors(length(bivn.kde2$z))[rank(bivn.kde2$z)]
persp3d(x=bivn.kde, col = col1)
with(bivn.kde2, surface3d(x,y,z, color = col2))
If you want to plot difference between two surfaces then you can do something like below.
res <- list(x = bivn.kde$x, y = bivn.kde$y, z = bivn.kde$z - bivn.kde2$z)
col3 <- heat.colors(length(res$z))[rank(res$z)]
persp3d(res, col = col3)
I have 3D matrix of floating point numbers and I would like to produce a smoothed 3D surface of this matrix using R. Any suggestions are welcome. Thanks
Now I am using scatterplot3d ... But this function did not produce a smoothed surface
x<-read.table("/Users/me/Desktop/data.txt")
scatterplot3d(x$V1, x$V2, x$V3, highlight.3d = TRUE, angle = 30, col.axis = "blue", col.grid = "lightblue", cex.axis = 1.3, cex.lab = 1.1, pch = 20)
I think that mba.surf from the MBA package would be a good choice for the smoothing, and as larrydag above suggests, persp would be good to image it. The code below is from the help page for the mba.surf function (swap LIDAR for your 3 column dataframe):
data(LIDAR)
mba.int <- mba.surf(LIDAR, 300, 300, extend=TRUE)$xyz.est
# Two ways of imaging....
image(mba.int, xaxs="r", yaxs="r")
persp(mba.int, theta = 135, phi = 30, col = "green3", scale = FALSE,
ltheta = -120, shade = 0.75, expand = 10, border = NA, box = FALSE)
If you are able to create a 2D matrix (x,y) with the value being the z-axis value you could use the following
persp
Here is an example from R Graph Gallery. persp example
require(misc3d)
a <- 2/5
wsqr <- 1 - a^2
w <- sqrt(wsqr)
denom <- function(a,w,u,v) a*((w*cosh(a*u))^2 + (a*sin(w*v))^2)
fx <- function(u,v) -u + (2*wsqr*cosh(a*u)*sinh(a*u)/denom(a,w,u,v))
fy <- function(u,v) 2*w*cosh(a*u)*(-(w*cos(v)*cos(w*v)) - (sin(v)*sin(w*v)))/denom(a,w,u,v)
fz = function(u,v) 2*w*cosh(a*u)*(-(w*sin(v)*cos(w*v)) + (cos(v)*sin(w*v)))/denom(a,w,u,v)
parametric3d(fx = fx, fy = fy, fz = fz,
umin = -17,
umax = 17,
vmin = -77,
vmax = 77,
n = 100,
color = c("grey17","grey21","red4","darkred","red4","grey21","grey17"),
engine = "rgl")
I'd like to do a vertical histogram. Ideally I should be able to put multiple on a single plot per day.
If this could be combined with quantmod experimental chart_Series or some other library capable of drawing bars for a time series that would be great. Please see the attached screenshot. Ideally I could plot something like this.
Is there anything built in or existing libraries that can help with this?
I wrote something a year or so ago to do vertical histograms in base graphics. Here it is, with a usage example.
VerticalHist <- function(x, xscale = NULL, xwidth, hist,
fillCol = "gray80", lineCol = "gray40") {
## x (required) is the x position to draw the histogram
## xscale (optional) is the "height" of the tallest bar (horizontally),
## it has sensible default behavior
## xwidth (required) is the horizontal spacing between histograms
## hist (required) is an object of type "histogram"
## (or a list / df with $breaks and $density)
## fillCol and lineCol... exactly what you think.
binWidth <- hist$breaks[2] - hist$breaks[1]
if (is.null(xscale)) xscale <- xwidth * 0.90 / max(hist$density)
n <- length(hist$density)
x.l <- rep(x, n)
x.r <- x.l + hist$density * xscale
y.b <- hist$breaks[1:n]
y.t <- hist$breaks[2:(n + 1)]
rect(xleft = x.l, ybottom = y.b, xright = x.r, ytop = y.t,
col = fillCol, border = lineCol)
}
## Usage example
require(plyr) ## Just needed for the round_any() in this example
n <- 1000
numberOfHists <- 4
data <- data.frame(ReleaseDOY = rnorm(n, 110, 20),
bin = as.factor(rep(c(1, 2, 3, 4), n / 4)))
binWidth <- 1
binStarts <- c(1, 2, 3, 4)
binMids <- binStarts + binWidth / 2
axisCol <- "gray80"
## Data handling
DOYrange <- range(data$ReleaseDOY)
DOYrange <- c(round_any(DOYrange[1], 15, floor),
round_any(DOYrange[2], 15, ceiling))
## Get the histogram obects
histList <- with(data, tapply(ReleaseDOY, bin, hist, plot = FALSE,
breaks = seq(DOYrange[1], DOYrange[2], by = 5)))
DOYmean <- with(data, tapply(ReleaseDOY, bin, mean))
## Plotting
par(mar = c(5, 5, 1, 1) + .1)
plot(c(0, 5), DOYrange, type = "n",
ann = FALSE, axes = FALSE, xaxs = "i", yaxs = "i")
axis(1, cex.axis = 1.2, col = axisCol)
mtext(side = 1, outer = F, line = 3, "Length at tagging (mm)",
cex = 1.2)
axis(2, cex.axis = 1.2, las = 1, line = -.7, col = "white",
at = c(75, 107, 138, 169),
labels = c("March", "April", "May", "June"), tck = 0)
mtext(side = 2, outer = F, line = 3.5, "Date tagged", cex = 1.2)
box(bty = "L", col = axisCol)
## Gridlines
abline(h = c(60, 92, 123, 154, 184), col = "gray80")
biggestDensity <- max(unlist(lapply(histList, function(h){max(h[[4]])})))
xscale <- binWidth * .9 / biggestDensity
## Plot the histograms
for (lengthBin in 1:numberOfHists) {
VerticalHist(binStarts[lengthBin], xscale = xscale,
xwidth = binWidth, histList[[lengthBin]])
}
Violin plots might be close enough to what you want. They are density plots that have been mirrored through one axis, like a hybrid of a boxplot and a density plot. (Much easier to understanding by example than description. :-) )
Here is a simple (somewhat ugly) example of the ggplot2 implementation of them:
library(ggplot2)
library(lubridate)
data(economics) #sample dataset
# calculate year to group by using lubridate's year function
economics$year<-year(economics$date)
# get a subset
subset<-economics[economics$year>2003&economics$year<2007,]
ggplot(subset,aes(x=date,y=unemploy))+
geom_line()+geom_violin(aes(group=year),alpha=0.5)
A prettier example would be:
ggplot(subset,aes(x=date,y=unemploy))+
geom_violin(aes(group=year,colour=year,fill=year),alpha=0.5,
kernel="rectangular")+ # passes to stat_density, makes violin rectangular
geom_line(size=1.5)+ # make the line (wider than normal)
xlab("Year")+ # label one axis
ylab("Unemployment")+ # label the other
theme_bw()+ # make white background on plot
theme(legend.position = "none") # suppress legend
To include ranges instead of or in addition to the line, you would use geom_linerange or geom_pointrange.
If you use grid graphics then you can create rotated viewports whereever you want them and plot to the rotated viewport. You just need a function that will plot using grid graphics into a specified viewport, I would suggest ggplot2 or possibly lattice for this.
In base graphics you could write your own function to plot the rotated histogram (modify the plot.histogram function or just write your own from scratch using rect or other tools). Then you can use the subplot function from the TeachingDemos package to place the plot wherever you want on a larger plot.