How to scale homogenously and completely a lattice xyplot in R? - r

I need to produce a lattice xyplot and fit it in a 8 cm x 8 cm pdf document.
I already made this plot. It is perfectly proportional on a 7 in x 7 in graph. I have been trying to scale it proportionally to a 8 cm x 8 cm graph, but with little success: the command "scales" works only on axis font label (but not on ticks length for instance), a standard "cex" in the xyplot works only on symbol size. I'd like to scale proportionally the whole plot (distance of labels from axis, tick lengths, legend etc...).
Thanks!
Here is a possible code:
# libraries
library(lattice)
library(grid)
library(RColorBrewer)
#creating dataset
x <- rnorm(100,10,3)
y <- rnorm(100,3,10)
z <- seq(1,100)
data <- data.frame(x,y)
data$z <- z
data$col <- heat.colors(100)
#making well scaled plot
pdf("plot.pdf")
my.legend <- packGrob(
draw.colorkey(key=list(col = heat.colors,at = do.breaks(range(data$z,na.rm=T),100))),
textGrob(expression(paste("z (no units)")), x = -.3, y = 0.5, just = c("left", "centre")),
height=unit(2, "lines"),side="top", dynamic=T)
xyplot(y~x, data, aspect="fill", type=c("p","g"), pch=21, col=grey(.2), fill=data$col, xlab=list(label=expression(paste("x axis label"[bla],", ",mu,"-"))),ylab=list(label=expression(paste("y axis label"[bla],", ",mu,"-"))),
legend=list(right=list(fun=my.legend)),
panel=function(x,y,...){
panel.xyplot(x,y,...)
}
)
dev.off()
#trying to make a 8cm x 8cm plot
pdf("plot_small.pdf",width=8/2.54,height=8/2.54)
my.legend <- packGrob(
draw.colorkey(key=list(col = heat.colors,at = do.breaks(range(data$z,na.rm=T),100))),
textGrob(expression(paste("z (no units)")), x = -.3, y = 0.5, just = c("left", "centre")),
height=unit(2, "lines"),side="top", dynamic=T)
xyplot(y~x, data, aspect="fill", type=c("p","g"), pch=21, col=grey(.2), fill=data$col, cex=.5, xlab=list(label=expression(paste("x axis label"[bla],", ",mu,"-")),cex=.5),ylab=list(label=expression(paste("y axis label"[bla],", ",mu,"-")),cex=.5),
legend=list(right=list(fun=my.legend)),
panel=function(x,y,...){
panel.xyplot(x,y,...)
},
scales=list(cex=.5)
)
dev.off()

Related

R levelplot adjust colour scale

I am trying to adjust my colour scale on a level plot using the rasterVis package. My code plots a raster. I am using manually set colour scale that classifies that data into 5 quantiles. I would like to have the labels stay at the values I have set, but instead of a linear scale as it appears now, have equal space between the labels. Is this possible with levelplot??
cor = M[, c("lon", "lat")]
sPDF <- SpatialPointsDataFrame (cor, data=M)
proj4string(sPDF)<-(p$geog.proj)
#Create Rasters
grid.sum <- rasterize(x=sPDF, y=grid, field=v, fun=grid.fun)
#Define colour scale
z <- getValues(grid.sum)
z <- z[is.finite(z)]
z <- round(z, digits=0)
quant <- unique(quantile(z, seq(0,1, length.out=75)))
quant.small <- unique(quantile(z, seq(0,1, length.out=5)))
ckey <- list(at=quant, labels=list(at=quant.small))
print(
levelplot(grid.sum, at=quant, colorkey=ckey, col.regions=p$seis,
alpha.regions=1, margin=F, xlab="", ylab="", main=name,
scales = list(x=list(cex=0.7), y=list(cex=0.7)))
+ layer(sp.polygons(coast, fill='lightgrey', alpha = 0.2))
+ layer(sp.lines(contours, col='dimgrey', alpha=0.6, lwd= 0.4)))

How to do a 3D plot using R?

I want to plot a 3D plot using R. My data set is independent, which means the values of x, y, and z are not dependent on each other. The plot I want is given in this picture:
This plot was drawn by someone using MATLAB. How can I can do the same kind of Plot using R?
Since you posted your image file, it appears you are not trying to make a 3d scatterplot, rather a 2d scatterplot with a continuous color scale to indicate the value of a third variable.
Option 1: For this approach I would use ggplot2
# make data
mydata <- data.frame(x = rnorm(100, 10, 3),
y = rnorm(100, 5, 10),
z = rpois(100, 20))
ggplot(mydata, aes(x,y)) + geom_point(aes(color = z)) + theme_bw()
Which produces:
Option 2: To make a 3d scatterplot, use the cloud function from the lattice package.
library(lattice)
# make some data
x <- runif(20)
y <- rnorm(20)
z <- rpois(20, 5) / 5
cloud(z ~ x * y)
I usually do these kinds of plots with the base plotting functions and some helper functions for the color levels and color legend from the sinkr package (you need the devtools package to install from GitHib).
Example:
#library(devtools)
#install_github("marchtaylor/sinkr")
library(sinkr)
# example data
grd <- expand.grid(
x=seq(nrow(volcano)),
y=seq(ncol(volcano))
)
grd$z <- c(volcano)
# plot
COL <- val2col(grd$z, col=jetPal(100))
op <- par(no.readonly = TRUE)
layout(matrix(1:2,1,2), widths=c(4,1), heights=4)
par(mar=c(4,4,1,1))
plot(grd$x, grd$y, col=COL, pch=20)
par(mar=c(4,1,1,4))
imageScale(grd$z, col=jetPal(100), axis.pos=4)
mtext("z", side=4, line=3)
par(op)
Result:

Plotting marginal histograms (as factors) and scatterplot (as numeric) from the same variable in R

I'm trying to create a scatterplot with marginal histograms as in this question.
My data are two (numeric) variables which share seven discrete (somewhat) logarithmically-spaced levels.
I've successfully done this with the help of ggMarginal in the ggExtra package, however I'm not happy with the outcome as when plotting the marginal histograms using the same data as for the scatterplots, things don't line up.
As can be seen below, the histogram bars are biased a little to the right or left of the datapoints themselves.
library(ggMarginal)
library(ggplot2)
x <- rep(log10(c(1,2,3,4,5,6,7)), times=c(3,7,12,18,12,7,3))
y <- rep(log10(c(1,2,3,4,5,6,7)), times=c(3,1,13,28,13,1,3))
d <- data.frame("x" = x,"y" = y)
p1 <- ggMarginal(ggplot(d, aes(x,y)) + geom_point() + theme_bw(), type = "histogram")
A possible solution for this may be change the variables used in the histograms into factors, so they are nicely aligned with the scatterplot axes.
This works well when creating histograms using ggplot:
p2 <- ggplot(data.frame(lapply(d, as.factor)), aes(x = x)) + geom_histogram()
However, when I try to do this using ggMarginal, I do not get the desired result - it appears that the ggMarginal histogram is still treating my variables as numeric.
p3 <- ggMarginal(ggplot(d, aes(x,y)) + geom_point() + theme_bw(),
x = as.factor(x), y = as.factor(y), type = "histogram")
How can I ensure my histogram bars are centred over the data points?
I'm absolutely willing to accept an answer which does not involve use of ggMarginal.
Not sure if it is a good idea to replicate here the answer I gave to the question you mentioned but I have no rights to comment still, please let me know otherwise.
I've found the package (ggpubr) that seems to work very well for this problem and it considers several possibilities to display the data.
The link to the package is here, and in this link you will find a nice tutorial to use it. For completeness, I attach one of the examples I reproduced.
I first installed the package (it requires devtools)
if(!require(devtools)) install.packages("devtools")
devtools::install_github("kassambara/ggpubr")
For the particular example of displaying different histograms for different groups, it mentions in relation with ggExtra: "One limitation of ggExtra is that it can’t cope with multiple groups in the scatter plot and the marginal plots. In the R code below, we provide a solution using the cowplot package." In my case, I had to install the latter package:
install.packages("cowplot")
And I followed this piece of code:
# Scatter plot colored by groups ("Species")
sp <- ggscatter(iris, x = "Sepal.Length", y = "Sepal.Width",
color = "Species", palette = "jco",
size = 3, alpha = 0.6)+
border()
# Marginal density plot of x (top panel) and y (right panel)
xplot <- ggdensity(iris, "Sepal.Length", fill = "Species",
palette = "jco")
yplot <- ggdensity(iris, "Sepal.Width", fill = "Species",
palette = "jco")+
rotate()
# Cleaning the plots
sp <- sp + rremove("legend")
yplot <- yplot + clean_theme() + rremove("legend")
xplot <- xplot + clean_theme() + rremove("legend")
# Arranging the plot using cowplot
library(cowplot)
plot_grid(xplot, NULL, sp, yplot, ncol = 2, align = "hv",
rel_widths = c(2, 1), rel_heights = c(1, 2))
Which worked fine for me:
If you are willing to give baseplotting a try, here is a function:
plots$scatterWithHists <- function(x, y, histCols=c("lightblue","lightblue"), lhist=20, xlim=range(x), ylim=range(y), ...){
## set up layout and graphical parameters
layMat <- matrix(c(1,4,3,2), ncol=2)
layout(layMat, widths=c(5/7, 2/7), heights=c(2/7, 5/7))
ospc <- 0.5 # outer space
pext <- 4 # par extension down and to the left
bspc <- 1 # space between scatter plot and bar plots
par. <- par(mar=c(pext, pext, bspc, bspc), oma=rep(ospc, 4)) # plot parameters
## barplot and line for x (top)
xhist <- hist(x, breaks=seq(xlim[1], xlim[2], length.out=lhist), plot=FALSE)
par(mar=c(0, pext, 0, 0))
barplot(xhist$density, axes=FALSE, ylim=c(0, max(xhist$density)), space=0, col=histCols[1])
## barplot and line for y (right)
yhist <- hist(y, breaks=seq(ylim[1], ylim[2], length.out=lhist), plot=FALSE)
par(mar=c(pext, 0, 0, 0))
barplot(yhist$density, axes=FALSE, xlim=c(0, max(yhist$density)), space=0, col=histCols[2], horiz=TRUE)
## overlap
dx <- density(x)
dy <- density(y)
par(mar=c(0, 0, 0, 0))
plot(dx, col=histCols[1], xlim=range(c(dx$x, dy$x)), ylim=range(c(dx$y, dy$y)),
lwd=4, type="l", main="", xlab="", ylab="", yaxt="n", xaxt="n", bty="n"
)
points(dy, col=histCols[2], type="l", lwd=3)
## scatter plot
par(mar=c(pext, pext, 0, 0))
plot(x, y, xlim=xlim, ylim=ylim, ...)
}
Just do:
scatterWithHists(x,y, histCols=c("lightblue","orange"))
And you get:
If you absolutely want to use ggMargins then look up xparams and yparams. It says you can send additional arguments to x-margin and y-margin using those. I was only successful in sending trivial things like color. But maybe sending something like xlim would help.

R: Plotting a scatterplot over a filled.contour plot

I am very new to R and have made a filled.contour plot using interpolated data like the data found in Plotting contours on an irregular grid . Using some sample data from Plotting contours on an irregular grid , I made a filled.contour and simple scatterplot using the following codes
x <- datr$Lat
y <- datr$Lon
z <- datr$Rain
require(akima)
fld <- interp(x,y,z)
filled.contour(fld)
plot(x,y)
Is there a way to make the plot(x,y) and filled.contour(fld) on the same plot (overlaying)? I have tried the points(x,y), but this doesn't match the x and y axes. In Matlab, I believe I would do this with hold, but I am unsure how to do it on R.
Thanks!
You could use the arguments plot.title or plot.axes for that:
x <- 10*1:nrow(volcano)
y <- 10*1:ncol(volcano)
filled.contour(x, y, volcano, plot.title = {
points(x = 200, y = 200)
})
(via)
One way is to read the code for filled.contour, and do a
little hacking like so:
Make your figure:
filled.contour(fld)
Define these constants by copying them from the arguments list.
nlevels = 20
zlim = range(z, finite = TRUE)
las = 1
levels = pretty(zlim, nlevels)
xlim = range(x, finite = TRUE)
ylim = range(y, finite = TRUE)
xaxs = "i"
yaxs = "i"
asp = NA
Calculate these values by copying code from the function body
mar.orig <- (par.orig <- par(c("mar", "las", "mfrow")))$mar
w <- (3 + mar.orig[2L]) * par("csi") * 2.54
Set the layout by copying code from the function body
layout(matrix(c(2, 1), ncol = 2L), widths = c(1, lcm(w)))
Noteice that the figure is actually plotted after the color scale,
but we don't wnat to reverse the order of the layout because layout
actually sets the 'current' region as the last region because the
first call to plot.new will cause the current region to wrap around
to the first region. Hence, when you set the plot window and plot the points via:
plot.window(ylim=ylim,xlim=xlim)
points(x,y)
title(main='title',
sub='Sub-Title',
xlab='This is the x axis',
ylab='This is the y axis')
They overlay figure as desired.

Make dotplot scale y axis as for histogram

We are using dotplots in a classroom setting to introduce the histogram, because the binning concept is confusing to many students. So we start with the dotplot which is similar but more intuitive:
x <- rnorm(100)
qplot(x, geom = "bar")
qplot(x, geom = "dotplot", method="histodot")
Because students do this on their own data, the code needs to work without manual fiddling. However the geom_dotplot seems to use different scaling defaults than geom_bar. The y axis does not adjust with the data, but seems to depend only on the size of the dots. For example:
x <- runif(1000)
qplot(x, geom = "bar")
qplot(x, geom = "dotplot", method="histodot")
How can I make geom_dotplot with stat_histodot scale the y axis exactly as it would do for the histogram, either by using smaller or overlapping dots?
I came up with the following workaround that shrinks the binwidth until things fit on the page:
# This function calculates a default binwidth that will work better
# for the dotplot with large n than the ggplot2 default.
calculate_smart_binwidth <- function(x, aspect_ratio = 2/3){
x <- as.numeric(x)
nbins <- max(30, round(sqrt(length(x)) / aspect_ratio))
range <- range(x, na.rm = TRUE, finite = TRUE)
if(diff(range) == 0) return(NULL)
repeat {
message("trying nbins: ", nbins)
binwidth <- diff(range)/nbins;
highest_bin <- max(ggplot2:::bin(x, binwidth = binwidth)$count);
if(highest_bin < aspect_ratio * nbins) return(binwidth)
nbins <- ceiling(nbins * 1.03);
}
}
Examples:
x <- runif(1e4)
qplot(x, geom="dotplot", binwidth=calculate_smart_binwidth(x))
x <- rnorm(1e4)
qplot(x, geom="dotplot", binwidth=calculate_smart_binwidth(x))

Resources