sanitize lattice axis labels for tikz device - r

I'm trying to knit a lattice contourplot into a PDF document using knitr and the tikz device but am getting an Error in getMetricsFromLaTeX(TeXMetrics) on compile. Here's the minimal reproducible example:
\documentclass{article}
\begin{document}
<<contourplot,dev='tikz',echo=FALSE>>=
library(lattice)
library(RCurl)
x <- getURL("https://dl.dropboxusercontent.com/u/3966900/likelihoods.csv")
likelihoods <- read.csv(text=x)
cutoffs <- c(- Inf,-2700,-1497,-1486.6,-1486.3,-1486.286,-1486.28513,-1486.285082,-1486.28508033,-1486.285080237, Inf)
contourplot(ll ~ var1*var2,
data = likelihoods,
scales = list(y = list(log = 10)),
at=cutoffs,
label.style='align',
labels=as.character(cutoffs),
xlab='$\\\\\\sigma$')
#
\end{document}
The whole thing works if I remove the scales line (I assume it's the ^ in the axis labels that trips tikz up?) but looks like shit.
It also works if I add sanitize=TRUE to the chunk options and remove two backslashes from the xlab string. In this case, however, the axis label also gets sanitized and I don't get a LaTeX-typeset axis label.
How do I get all of this to work?

To sanitize the axis labels, modify the scales argument in the following way:
# e-notation (like ggplot2)
scales = list(y = list(log=10, at=10**seq(5, 15, 5))))
or
scales = list(y = list(log=10, at=10**seq(5, 15, 5),
label=sprintf("$10^{%d}$", seq(5, 15, 5))))

As Andy Clifton suggests in comments, doing this with ggplot seems to be a hell of a lot easier than getting it to work with lattice:
\documentclass{article}
\begin{document}
<<contourplot,dev='tikz',echo=FALSE,warning=FALSE>>=
library(ggplot2)
library(scales)
library(RCurl)
x <- getURL("https://dl.dropboxusercontent.com/u/3966900/likelihoods.csv")
likelihoods <- read.csv(text=x)
cutoffs <- c(-Inf,-2700,-1497,-1486.6,-1486.3,-1486.286,-1486.28513,-1486.285082,-1486.28508033,-1486.285080237,Inf)
v <- ggplot(likelihoods, aes(var1, var2, z = ll))
v <- v + stat_contour(breaks=cutoffs)
v <- v + scale_y_continuous(trans=log10_trans(),
breaks=c(1e-5,1e0,1e5,1e10,1e15,1e20),
expand = c(0, 0))
v <- v + scale_x_continuous(limits = c(-3, 5),
expand = c(0, 0))
v <- v + theme_bw()
v <- v + ylab('$\\sigma$')
v
#
\end{document}

Related

image.plot in R not displaying colorscale values at the edges of color scale

[
Notice the diff in color scale label on two images. top image is the output from R 3.2.5, same code produces bottom image in R 2.15.2. I want to resolve the 'shift' of labels in the top plot to match the bottom one. Sample code given in this query was used to generate both plots.
I am trying to plot a map using image.plot but the min and max value of colorscale are not displayed exactly at the tips. I am facing this issue in R version 3.2.5 (2016-04-14); Platform: x86_64-w64-mingw32/x64 (64-bit) and library package 'fields' Spam version 1.4-0 (2016-08-29)
In contrast, the same commands could be correctly displayed the min and max values at the edges of color scale in R version 2.15.2 (2012-10-26), Platform: x86_64-w64-mingw32/x64 (64-bit) and 'fields' package 0.41-0 (2014-02-26). Here is sample code:
library(fields)
temp <- matrix(data=rexp(200, rate=10), nrow=180, ncol=360)
min(temp)
max(temp)
color_plate <- c("#FF0000", "#FF4D00", "#FF7000", "#FF8A00", "#FFA800", "#FFBF00", "#FFF000", "#FFFF54", "#AAFFFF","#7FFFFF", "#55FFFF", "#2AFFFF", "#00CFFF", "#20BFFF", "#209FFF", "#2060FF")
zlim <- seq(0.08,0.40,by=0.04)
temp[temp<min(zlim)] <- min(zlim)
temp[temp>max(zlim)] <- max(zlim)
image.plot(temp,col=color_plate,
axis.args=list(cex.axis =1,at=zlim, labels=zlim,mgp=c(1, 0, 0),tck=0.1))
The best I could do to answer this question was to escape the confines of image.plot()and recode the heat map in ggplot2. The code I wrote should relocate your tick marks to the appropriate locations. Note that "Var1" and "Var2" in the ggplot object p can be switched depending on how you want the data displayed. I used melt() to transform the temp object which means that the original row/column designation is lost. I wasn't sure which plotted on the x/y axis in the image.plot() function, so if I chose the wrong one be sure to switch "Var1" and "Var2".
I hope this helps!
library(fields)
library(reshape2)
library(ggplot2)
library(grid)
temp <- matrix(data=rexp(200, rate=10), nrow=180, ncol=360)
color_palette <- c("#FF0000", "#FF4D00", "#FF7000", "#FF8A00",
"#FFA800", "#FFBF00", "#FFF000", "#FFFF54", "#AAFFFF","#7FFFFF",
"#55FFFF", "#2AFFFF", "#00CFFF", "#20BFFF", "#209FFF", "#2060FF")
zlim <- seq(0.08,0.40,by=0.04)
zlim2 <- seq(0.08,0.40,by=0.02)
temp[temp<min(zlim)] <- min(zlim)
temp[temp>max(zlim)] <- max(zlim)
rownames(temp) <- seq(0,1,1/(length(temp[,1])-1))
colnames(temp) <- seq(0,1,1/(length(temp[1,])-1))
tdm <- melt(temp)
tdm$val_for_color <- NA
##can change this as long as you end up with 17 classes (labeled 1-17) for color assignment
for(i in 1:(length(zlim2)-1)){
tdm$val_for_color[which(tdm$value >= zlim2[[i]] & tdm$value <= zlim2[[i+1]] )] <- i
}
p <- ggplot(tdm, aes(x = Var1, y = Var2, fill = val_for_color)) +
geom_raster() + scale_fill_gradientn(breaks=seq(1,length(zlim),1),colors=color_palette, labels=zlim)+
scale_x_continuous(expand=c(0,0)) +
scale_y_continuous(expand=c(0,0)) +
guides(fill = guide_colorbar(draw.ulim = TRUE,draw.llim = FALSE,
barwidth = 0.7, barheight = 10, limits=c(min(zlim),max(zlim)), raster=FALSE,
ticks=FALSE,
title=NULL))+
ylab(NULL)+
xlab(NULL)+
theme_bw()
g <- ggplotGrob(p)
#this shifts and spreads the labels
d <-g$grobs[[15]][[1]][[1]]$grobs[[3]]$y[[1]]
g$grobs[[15]][[1]][[1]]$grobs[[3]]$y[[1]] <- g$grobs[[15]][[1]][[1]]$grobs[[3]]$y[[1]]-d
for(i in 2:length(g$grobs[[15]][[1]][[1]]$grobs[[3]]$y)){
g$grobs[[15]][[1]][[1]]$grobs[[3]]$y[[i]] <- d*5*(i-1)
}
grid.draw(g)
I got the answer from package creator of fields package. Pasting the sample code here for others..
library(fields)
temp <- matrix( seq( 0,.5,,80), 8,10)
colTab <- c("#FF0000", "#FF4D00","#FF7000", "#FF8A00", "#FF7000")
N<- length( colTab)
breaks <- seq(0.08, 0.40, length.out= N+1 )
image.plot(temp, col=colTab, breaks=breaks,
axis.args=list(cex.axis =1, at=breaks, labels= breaks, mgp=c(1, 0, 0), tck=0.1)
)

Rasterise ggplot images in R for tikzdevice

I use R to analyse data, ggplot to create plots, tikzDevice to print them and finally latex to create a report. THe problem is that large plots with many points fail due to the memory limit of latex. I found here https://github.com/yihui/tikzDevice/issues/103 a solution that rasterises the plot before printing the tikz file, which allows printing the points and the text individually.
require(png)
require(ggplot2)
require(tikzDevice)
## generate data
n=1000000; x=rnorm(n); y=rnorm(n)
## first try primitive
tikz("test.tex",standAlone=TRUE)
plot(x,y)
dev.off()
## fails due to memory
system("pdflatex test.tex")
## rasterise points first
png("inner.png",width=8,height=6,units="in",res=300,bg="transparent")
par(mar=c(0,0,0,0))
plot.new(); plot.window(range(x), range(y))
usr <- par("usr")
points(x,y)
dev.off()
# create tikz file with rasterised points
im <- readPNG("inner.png",native=TRUE)
tikz("test.tex",7,6,standAlone=TRUE)
plot.new()
plot.window(usr[1:2],usr[3:4],xaxs="i",yaxs="i")
rasterImage(im, usr[1],usr[3],usr[2],usr[4])
axis(1); axis(2); box(); title(xlab="x",ylab="y")
dev.off()
## this works
system("pdflatex test.tex")
## now with ggplot
p <- ggplot(data.frame(x=x, y=y), aes(x=x, y=y)) + geom_point()
## what here?
In this example the first pdflatex fails. The second succeeds due to the rasterisation.
How can I apply this using ggplot?
here's a proof-of-principle to illustrate the steps that would be involved. As pointed out in the comments it's not recommendable or practical, but could be the basis of a lower-level implementation.
require(png)
require(ggplot2)
require(tikzDevice)
n=100;
d <- data.frame(x=rnorm(n), y=rnorm(n), z=rnorm(n))
p <- ggplot(d, aes(x=x, y=y, colour=z, size=z, alpha=x)) + geom_point()
## draw the layer by itself on a png file
library(grid)
g <- ggplotGrob(p)
# grid.newpage()
gg <- g$grobs[[6]]$children[[3]]
gg$vp <- viewport() # don't ask me
tmp <- tempfile(fileext = "png")
png(tmp, width=10, height=4, bg = "transparent", res = 30, units = "in")
grid.draw(gg)
dev.off()
## import it as a raster layer
rl <- readPNG(tmp, native = TRUE)
unlink(tmp)
## add it to a plot - note that the positions match,
## but the size can be off unless one ensures that the panel has the same size and aspect ratio
ggplot(d, aes(x=x, y=y)) + geom_point(shape="+", colour="red") +
annotation_custom(rasterGrob(rl, width = unit(1,"npc"), height=unit(1,"npc"))) +
geom_point(aes(size=z), shape=1, colour="red", show.legend = FALSE)
## to illustrate the practical use, we use a blank layer to train the scales
## and set the panel size to match the png file
pf <- ggplot(d, aes(x=x, y=y)) + geom_blank() +
annotation_custom(rasterGrob(rl, width = unit(1,"npc"), height=unit(1,"npc"), interpolate = FALSE))
tikz("test.tex", standAlone=TRUE)
grid.draw(egg::set_panel_size(pf, width=unit(10, "cm"), height=unit(4, "cm")))
dev.off()
system("lualatex test.tex")
system("open test.pdf")
we can zoom in and check that the text is vector-based while the layer is (here low-res for demonstration) raster.
ok, I will write it here because it was too big for the comment box. Instead of adding the rasterised points to a nw plot with new scales you can actually replace the original grob with the rasterised grob by
g$grobs[[6]]$children[[3]] <- rasterGrob(rl). The problem is that it doesn't scale, so you have to know the size of the final image before. Then you can sue sth like this:
rasterise <- function(ggp,
width = 6,
height = 3,
res.raster = 300,
raster.id= c(4,3),
file = ""){
## RASTERISE
require(grid)
require(png)
## draw the layer by itself on a png file
gb <- ggplot_build(ggp)
gt <- ggplot_gtable(gb)
## calculate widths
h <- as.numeric(convertUnit(sum(gt$heights), unitTo="in"))
w <- as.numeric(convertUnit(sum(gt$widths) , unitTo="in"))
w.raster <- width-w
h.raster <- height-h
## print points as png
grid.newpage()
gg <- gt$grobs[[raster.id[1]]]$children[[raster.id[2]]]
gg$vp <- viewport() # don't ask me
tmp <- tempfile(fileext = "png")
png(tmp, width=w.raster, height=h.raster, bg = "transparent", res = res.raster, units = "in")
grid.draw(gg)
dev.off()
## import it as a raster layer
points <- readPNG(tmp, native = TRUE)
points <- rasterGrob(points, width = w.raster, height = h.raster, default.units = "in")
unlink(tmp)
## ADD TO PLOT
gt$grobs[[raster.id[1]]]$children[[raster.id[2]]] <- points
## PLOT TMP
### HERE YOU CAN ONLY PRINT IT IN THIS DIMENSIONS!
pdf(file, width = width, height = height)
grid.draw(gt)
dev.off()
}
And then use it with
data <- data.frame(x = rnorm(1000), y = rnorm(1000))
plot <- ggplot(data, aes(x = x, y = y)) +
geom_point() +
annotate("text", x = 2, y = 2, label = "annotation")
rasterise(ggp = plot,
width = 6,
height = 3,
res.raster = 10,
raster.id = c(4,2),
file = "~/test.pdf")
The problem remains the ID of the grob you want to rasterise. I didn't figure out a good way to find the correct one automatically. It depends on which layers you add to the plot.

grid.arrange with filled.contour in R Studio

I created a few plots with the filled.contour function. Then I would like to plot two of the plots next to each other. Therefore I used the grid.arrange function.
This is my code:
install.packages("gridExtra")
install.packages("lattice")
install.packages("grid")
library(lattice)
library(gridExtra)
library(grid)
# Fake data
x <- c(1:10)
y <- c(1:10)
z<-matrix(data=c(1:100), nrow=10, ncol=10, byrow = FALSE)
p1<-filled.contour(x,y,z, color = terrain.colors, asp = 1) # simple
# Lay out both plots
grid.arrange(p1,p1, ncol=2)
But what I get is:
Error in gList(list(wrapvp = list(x = 0.5, y = 0.5, width = 1, height
= 1, : only 'grobs' allowed in "gList"
Thats why I tried this:
install.packages("gridExtra")
install.packages("lattice")
install.packages("grid")
library(lattice)
library(gridExtra)
library(grid)
# Fake data (taken from the fill.contour help examples)
x <- c(1:10)
y <- c(1:10)
z<-matrix(data=c(1:100), nrow=10, ncol=10, byrow = FALSE)
p1<-filled.contour(x,y,z, color = terrain.colors, asp = 1) # simple
p1<-grob(p1)
is.grob(p1)
# Lay out both plots
grid.arrange(p1,p1, ncol=2)
But this does not work either. Can you help me please?
As #eipi10 pointed out, filled.contour is base graphics, so you should use base arrangement functions, i.e. par(mfrow = c(1,2)) to arrange two plots side by side.
EDIT: apparently filled contour is famous for defeating all layout attempts. I tried par(plt...) layout() and par(mfrow...) I found filled.countour3 as a workaround as described here:
http://wiki.cbr.washington.edu/qerm/sites/qerm/images/e/ec/Example_4_panel_contour_plot_with_one_legend.R
and in question 14758391 on this site. Sorry for the confusion

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:

specific colours are required within Hexbin package?

I am plotting scatter plot for high density of dots.I used Hexbin package and I successfully plot the data.The colour is not pretty,and I am asked to follow a standard colour. I wonder if it is supported by R. Image shows my out put(right) and the wanted colour(left).
Example:
x <- rnorm(1000)
y <- rnorm(1000)
bin<-hexbin(x,y, xbins=50)
plot(bin, main="Hexagonal Binning")
Using the example on the package helpapge for hexbin you can get close using rainbow and playing with the colcuts argument like so...
x <- rnorm(10000)
y <- rnorm(10000)
(bin <- hexbin(x, y))
plot(hexbin(x, y + x*(x+1)/4),main = "Example" ,
colorcut = seq(0,1,length.out=64),
colramp = function(n) rev(rainbow(64)),
legend = 0 )
You will need to play with the legend specification etc to get exactly what you want.
Alternative colour palette suggested by #Roland
## nicer colour palette
cols <- colorRampPalette(c("darkorchid4","darkblue","green","yellow", "red") )
plot(hexbin(x, y + x*(x+1)/4), main = "Example" ,
colorcut = seq(0,1,length.out=24),
colramp = function(n) cols(24) ,
legend = 0 )

Resources