Rendering xtable with significant digits - r

I'd like to be able to render an xtable in an automatically run piece of code, i.e. NOT via copy-and-paste, while controlling the number of significant digits. The only way that I know to render an xtable on a standard plot device is by using grid.table, but that method ignores the digits directive and plots all available digits. Here's a code example. Any advice?
library(xtable)
library(gridExtra)
x = rnorm(100)
y = x + rnorm(100)
m = lm(y ~ x)
print(xtable(m)) #too many decimal places
print(xtable(m, digits = 2)) #this works
grid.table(xtable(m, digits=2)) #this doesn't!!!
None of the bits of advice here seem useful for automated rendering:
R: rendering xtable

If you convert everything to strings, you should be able to make this work:
x <- xtable(m)
x[] <- lapply(x, sprintf, fmt = "%0.2f")
grid.table(x)

I'm not sure of your final plot device, but for some purposes you can just skip xtable all together:
library("broom")
library("gridExtra")
x = rnorm(100)
y = x + rnorm(100)
m = lm(y ~ x)
DF <- broom::tidy(m)
DF[,2:4] <- round(DF[,2:4], 2)
DF[,5] <- format(DF[,5], scientific = TRUE, digits = 4)
grid.table(DF)
Make sure you have the latest gridExtra. You can also control the appearance of the table in great detail, via themes (there is a vignette on the topic).

Related

How can I change plotted numbers from scientific notation to standard form in an rpart regression tree plot?

I am using the rpart.plot package to plot a regression tree. How can change the numbers from scientific notation into standard form at the bottom of the tree? For example, I want to change 14e+3 to 14000.
This is the code I am using:
library(rpart.plot)
rpart.plot(tm1, type=5, digits = 2, fallen.leaves = T)
And here is the result:
This is a tricky one, because the package author decided to hard code in the scientific notation.
If we review the source code, there is a
function rpart.plot:::format0 that formats any values between 0.001 and 9999.
So one approach, is to create a copy that over-writes those default values and assign it into the rpart.plot namespace.
First, an example tree:
library(nycflights13)
library(rpart.plot)
fit <- rpart(carrier ~ origin + distance, data = flights[flights$carrier %in% c("UA","AA","DL"),])
rpart.plot(fit, type = 5, digits = 2, fallen.leaves = TRUE, extra = 101)
Note the scientific notation.
Now, we'll create the copy and call it myformat0. We need to use ::: for a couple of functions because they aren't exported from rpart.plot. Note that I replaced the 9999 with 100000, but you can use whatever number you want.
myformat0 <- function(x, digits=2)
{
rpart.plot:::check.integer.scalar(digits)
if(digits == 0)
digits <- getOption("digits")
if(digits >= 0)
rpart.plot:::formate(x, digits, smallest=.001, largest=100000)
else
sapply(x, format, digits=-digits)
}
Now we need to assign our custom function into the rpart.plot namespace. We can use assignInNamespace:
assignInNamespace("format0", myformat0, ns = "rpart.plot")
And now the plot:
rpart.plot(fit, type = 5, digits = 2, fallen.leaves = TRUE, extra = 101)

subscript after superscript using bquote in R

I am trying to plot a specific R-square metric, the R2 relative to the 1:1 line. Here are some code to generate data and a plot. (I realize I am only calculating standard r-squared here, but thats fine for the purposes of working out the code).
#generate data.
set.seed(1234)
x <- rnorm(100)
y <- x*0.7 + rnorm(100)
mod <- lm(y~x)
#develop rsq label.
rsq <- round(summary(mod)$r.squared, 2)
rsq.1.lab <- bquote(R^2 [1:1] == .(rsq))
#drop plot and rsq label.
plot(y ~ x)
mtext(rsq.1.lab, side = 3, line = -2, adj = 0.05)
The plot looks like this:
This is pretty close, but the subscript is actually relative to the superscript, rather than being relative to the letter R. How can I change this? Looking for solutions that use base R, ideally keeping bquote().
Use {/} grouping:
rsq.1.lab <- bquote({R^2} [1:1] == .(rsq))
or
rsq.1.lab <- bquote({R [1:1]}^2 == .(rsq))
or even a somewhat ridiculous
rsq.1.lab <- bquote(R * atop(2, "1:1") == .(rsq))
though we can reduce the font size a little using
rsq.1.lab <- bquote(R * scriptstyle(atop(2, "1:1")) == .(rsq))
Much of this is suggested/documented in ?plotmath.

Export R plot to multiple formats

Since it is possible to export R plots to PDF or PNG or SVG etc., is it also possible to export an R plot to multiple formats at once? E.g., export a plot to PDF and PNG and SVG without recalculating the plot?
Without using ggplot2 and other packages, here are two alternative solutions.
Create a function generating a plot with specified device and sapply it
# Create pseudo-data
x <- 1:10
y <- x + rnorm(10)
# Create the function plotting with specified device
plot_in_dev <- function(device) {
do.call(
device,
args = list(paste("plot", device, sep = ".")) # You may change your filename
)
plot(x, y) # Your plotting code here
dev.off()
}
wanted_devices <- c("png", "pdf", "svg")
sapply(wanted_devices, plot_in_dev)
Use the built-in function dev.copy
# With the same pseudo-data
# Plot on the screen first
plot(x, y)
# Loop over all devices and copy the plot there
for (device in wanted_devices) {
dev.copy(
eval(parse(text = device)),
paste("plot", device, sep = ".") # You may change your filename
)
dev.off()
}
The second method may be a little tricky because it requires non-standard evaluation. Yet it works as well. Both methods work on other plotting systems including ggplot2 simply by substituting the plot-generating codes for the plot(x, y) above - you probably need to print the ggplot object explicitly though.
Yes, absolutely! Here is the code:
library(ggplot2)
library(purrr)
data("cars")
p <- ggplot(cars, aes(speed, dist)) + geom_point()
prefix <- file.path(getwd(),'test.')
devices <- c('eps', 'ps', 'pdf', 'jpeg', 'tiff', 'png', 'bmp', 'svg', 'wmf')
walk(devices,
~ ggsave(filename = file.path(paste(prefix, .x)), device = .x))

knitr does not hook scientific notation in plots

When using knitr inline, it typos $\Sexpr{2.5e3}$ with $2.5 \times 10^3$ which is pretty nice. However I miss the fact that this does not work for the labels in plots. I guess knitr thinks there are character and not numeric. Is there a way to change that ?
As I discussed in the comments, getting this to happen automatically isn't so easy, but it's not too hard to get your scales translated. sfsmisc::eaxis() is a good solution for base plots. Here are some ggplot-style solutions:
If you want to use native ?plotmath-style formatting:
##scale function for plotting y-axis labels
scientific_10 <- function(x) {
s <- scales::scientific_format()(x)
## substitute for exact zeros
s[s=="0e+00"] <- "0"
## regex: [+]? = "zero or one occurrences of '+'"
parse(text=gsub("e[+]?", " %*% 10^", s ))
}
Or if you're using LaTeX/TikZ (I'm using Hmisc::latexSN() here. It's a 3-line function, so you could just copy it if you wanted to avoid dependencies or hack it):
scientific_latex <- function(x,scipen=-2) {
require(Hmisc)
op <- options(scipen=scipen) ## encourage use of scientific notation
on.exit(options(op)
s <- paste0("$",Hmisc::latexSN(x),"$")
}
Example:
set.seed(101)
d <- data.frame(trait=runif(1000),
time=runif(1000,0,1000))
library(ggplot2); theme_set(theme_bw())
## make plot
breaks.y<-seq(from=0, to=1000, by=200)
g0 <- ggplot(d,aes(trait,time))+
geom_point()
plotmath style:
g0 + scale_y_continuous(label=scientific_10,
breaks=breaks.y, limits=c(0,1000))
TikZ:
g0 + scale_y_continuous(label=scientific_latex,
breaks=breaks.y, limits=c(0,1000))
Well after #Ben Bolker comment, I add also my solution here, maybe more in the knitr mood as it is only sort of a hack to apply the knitrrendering to the axis label. Especially in a knitr document one often sets in the beginning digits and scipen and expects it to be applied everywhere.
So define in the setup chunk the function:
inline_hook <- function (x) {
if (is.numeric(x)) {
x = knitr:::format_sci(x, "latex")
i = grep("[^0-9.,]", x)
x[i] = sprintf("\\ensuremath{%s}", x[i])
if (getOption("OutDec") != ".")
x = sprintf("\\text{%s}", x)
}
if (is.numeric(x)) x = round(x, getOption("digits"))
x
}
which is just a mix of knitr::.inline.hook.tex and knitr:::.inline.hook with the final collapse discarded. Then modify the default behaviour of scale_y_continous according to this post:
scale_y_continuous <- function(...) ggplot2:::scale_y_continuous(..., labels=inline_hook)
Then from the above example:
set.seed(101)
d <- data.frame(trait=runif(1000),
time=runif(1000,0,1000))
library(ggplot2); theme_set(theme_bw())
## make plot
breaks.y<-seq(from=0, to=1000, by=200)
g0 <- ggplot(d,aes(trait,time))+
geom_point()
g0
I get by default:
which is exactly what knitr does to number given inline.

Force R to write scientific notations as n.nn x 10^-n with superscript

Let's say I have two floats
a <- 8.9384920e-24
b <- 0.00293892837
I would like to display either of them in 10-base scientific notation rounded to two decimals on a graph, possibly using paste(), but with superscript formatting after the 10.
8.94 x 10^-24 #no ^ and superscript font
2.94 x 10^-4 #no ^ and supercript font, should be -4, not -04
This is really maniac but it has been requested by a superior, it has to be done in base R (not ggplot2) or I will have to re-write 600 lines of code... Right now all I can see is that floats are printed differently depending on how big they are...
You may check eaxis in package sfsmisc
# some data
x <- seq(1, 100000, len = 10)
y <- seq(1e-5, 1e-4, len = 10)
# default axes
plot(x, y)
# eaxis
plot(x, y, axes = FALSE)
eaxis(side = 1)
eaxis(side = 2)
You may also create a label expression using pretty10exp() from the same package. For example to apply the format to a plot title:
plot(x, y, axes = FALSE)
title(pretty10exp(y[1]))

Resources