A library that outputs HTML grobs compatible with R's grid graphics? - r

I love Yihui's knitr package, and I know from the tutorials that it can put R into html documents. I want to go the other way -- I want to put some html into a grid graphics object. Is that possible in knitr, or any other library? Specifically, I am looking for a way to:
Style text using HTML (basic css and tables, mostly)
Wrap it up in a grob
Arrange/insert the grob using grid graphics, combining it with other grobs (ggplot charts, etc.)
I've searched on the knitr list and looked into grid graphics. It has a textGrob function but formatting options aren't robust enough for what I am looking for. There's a SO question that's in the ballpark but doesn't cover what I'm looking for. Here's a silly reproducible example that imitates the structure of my real document.
library(gridExtra)
#minimal valid object
rect = rectGrob()
text1 <- textGrob(
label = "textGrobs let you write text"
,x = unit(0.5, "npc"), y = unit(0.5, "npc")
,just = "centre"
,gp = gpar(col = "black", fontsize = 12)
)
text2 <- textGrob(
label = "but is there a graphics object that takes HTML?"
,x = unit(0.5, "npc"), y = unit(0.5, "npc")
,just = "centre"
,gp = gpar(col = "black", fontsize = 12)
)
#first split the box
top_box <- arrangeGrob(text1, text2, ncol = 2)
#put that together into a column
left_column <- arrangeGrob(
top_box, rect, rect
,nrow = 3
,heights = c(1, 2, 2)
)
grid.arrange(left_column, rect, widths = c(4/5, 1/5), ncol = 2)
I'd like to replace one of those empty rectangular grobs below with some text with HTML.
Thanks!

It's not clear what you mean by "an HTML grob". There is no HTML formatted object in your code. Certainly there are functions that can produce HTML and you could send that text to a grid.text call and display the HTML. I worry, however, that you intend to have some package display the HTML browser-like as a formatted table. The html function in Hmisc sends its output to a real browser. latex in Hmisc is designed for display. The tableGrob function in 'gridExtra' won't take HTML as a formatting specification. You might get further by examining the code and experimenting with xtable and print.xtable in the xtable package, since it is capable of delivering HTML output. You can also explore the latexTabular function in 'Hmisc' or the tabular function in the 'tables' package.

Related

Automatically adjust plot title width using ggplot

I am fairly new to R/ggplot2 and still learning on the go. Hopefully I am not missing something obvious!
I am trying to create several different plots using ggplot2 that I am layouting using the function plot_grid from the cowplot package to make the plots visible side by side and add plot numeration and captions. The problem is that if the generated plots are displayed in a small window or I have many plots beside one another then the titles of the two plots sometimes overlap. To solve this problem I tried to automatically insert line breaks in my too long titles using code I found in another thread since I wanted the text size of the titles to stay constant.
Using the following code I can easily automatically insert the necessary line breaks to make my title a specific width, but the problem is that I always need to enter a numeric value for the width. Depending on the number of plots I am inserting this value would of course change. I could of course go through my code and manually set the width for each set of plots until it is the correct value, but I was hoping to automate this process so that the title width is adjusted automatically to match the width of the x-axis. Is there anyway to implement this in R?
#automatically line break and add titles
myplot_theme1 = function (plot, x.title = NULL, y.title = NULL, plot.title = NULL) {
plot +
labs(title = paste(strwrap(plot.title, width = 50), collapse = "\n"),
x = x.title,
y = y.title)
}
# generate an example plot
data_plot <- data.frame(x = rnorm(1000), y = rnorm (1000))
plot1 <- ggplot(data_plot, aes(x = x, y = y)) + geom_point()
title <- "This is a title that is very long and does not display nicely"
myplot_theme1(plot1, plot.title = title)
My test plot
I have tried searching but I haven't found any solutions that seem to address what I am looking for. The only solution I did find that looked promising was based on the package gridDebug. This packages doesn't seem to be supported by my operating system anymore though (macOS Sierra Version 10.12.6) since when I try to install it I get the following error message:
Warning in install.packages: dependencies ‘graph’, ‘Rgraphviz’ are not available
And on the CRAN package documentation it states that the package is not even available for macOS El Capitan which was my previous operating system. If someone knows what is causing this issue so that I could try the solution from the above thread that would of course be great as well.
One idea (but perhaps not an ideal solution) is to adjust the size of text based on the number of characters in the title. You can adjust ggplot properties using theme and in this case you want to adjust plot.title (the theme property, not your variable). plot.title has elements size and horizontal justification hjust, the latter is in range [0,1].
# generate an example plot
data_plot <- data.frame(x = rnorm(1000), y = rnorm (1000))
plot1 <- ggplot(data_plot, aes(x = x, y = y)) + geom_point()
title1 <- "This is a title that is very long and does not display nicely"
title2 <- "I'm an even longer sentence just test me out and see if I display the way you want or you'll be sorry"
myplot_theme1 = function (plot, x.title = NULL, y.title = NULL, plot.title = NULL) {
plot +
labs(title = plot.title,
x = x.title,
y = y.title) +
theme(plot.title = element_text(size=800/nchar(plot.title), hjust=0.5)) # 800 is arbitrarily chosen
}
myplot_theme1(plot1, plot.title = title1)
myplot_theme1(plot1, plot.title = title2)

Define margins of PDF used for boxplot rendering

When I render a boxplot on a PDF device in R there is a large white space besides the graph, especially at the top that i intent to reduce.
My script is basically just:
data <- read.csv("input.csv")
pdf(file="output.pdf", width=4, height=5)
boxplot(data, xlab="input graphs", ylab="vertex count")
This leads to something like:
where the grey outline indicates the end of the document.
I tried to use the par attributes "mar" and "mai" as described in https://stat.ethz.ch/R-manual/R-devel/library/graphics/html/par.html but it had no effect.
boxplot(data, mar=c(0,0,0,0=, mai=c(0,0,0,0))
Do you have an advice how I can gain whitespace control? I want to have zero outer whitespace as the generated graph will be used in a Latex environment that provides sufficient spacings on its own. I am using Ubuntu as OS.
Define mar right after pdf. Try this as an example
pdf(file = "test.pdf", width = 5, height = 5)
par(mar = c(5, 5, 0.05, 0.05))
set.seed(42)
plot(rnorm(20))
dev.off()

Printing out a dataframe in R: grid.table outputs cropped tables, doesn't respond to fontsize

I am trying to automate a series of analyses which are intended to save a number of plots for later inspection. One of the plots will be accompanied by a table of values. I'd like to have them in the same pdf so that the users don't have to jump between files.
I have checked numerous questions on SO regarding outputting data frames to pdf, here are a couple of reasons why existing answers aren't satisfactory in my case:
Not familiar with knitr/Sweave
Batch generation of figures mean that I cannot do it manually via RStudio Viewer
grid.table based solutions do not generate the entire table.
Which brings me to my problems, say I have a table 48 x 5 in proportions. If I try to plot it out with grid.table(geno) it results in a cropped table showing some 20-30 rows in the middle. If I go with grid.table(geno, gp = gpar(fontsize=8)) to decrease the fontsize I get the following error message.
Error in gtable_table(d, name = "core", fg_fun = theme$core$fg_fun, bg_fun = theme$core$bg_fun, :
unused argument (gp = list(fontsize = 8)
)
Essentially I would like to be able to use it in this way:
library(grid)
library(gridExtra)
pdf(file="gtype.pdf", title = "Genotype data")
plotGenotype(geno, text_size = 10) # outputs a custom plot
grid.newpage()
grid.table(geno) # grid.table(geno, gp = gpar(fontsize=8))
dev.off()
The problem here is that I either get a cropped table or nothing at all, on the second page. I noticed that many people add height=11, width=8.5 to the pdf() call. I am not sure if/why that would make a difference but setting paper="a4" or height/width according to A4 does not make any difference in my case.
Q1: Is it not possible to get grid.table to resize based on content and not paper?
Q2: Is there some other way to get a data frame printed to a pdf without having to go through LaTeX based solutions?
(I am currently running R 3.3.1 and gridExtra 2.2.1)
Q1: Is it not possible to get grid.table to resize based on content and not paper?
It is possible, but generally not desirable. A table is meant to be read, and if text and spacings were determined by the page rather than the content, it would often yield unreadable results. Thus the usual advice: manually tweak the font size and padding, or split the table.
It is by no means a technical limitation: feel free to set the cell size to fit the page:
grid.newpage()
pushViewport(viewport(width=unit(0.8,"npc"), height=unit(0.8,"npc")))
g <- g2 <- tableGrob(iris[1:4, 1:3], cols = NULL, rows=NULL)
g2$heights <- unit(rep(1/nrow(g2), nrow(g2)), "npc")
grid.arrange(rectGrob(), rectGrob(), nrow=1, newpage = FALSE)
grid.arrange(g, g2, nrow=1, newpage = FALSE)
but with too much content for the page it's unclear what result is better
grid.newpage()
pushViewport(viewport(width=unit(0.8,"npc"), height=unit(0.8,"npc")))
g <- g2 <- tableGrob(iris[1:20, 1:3], cols = NULL, rows=NULL)
g3 <- tableGrob(iris[1:20, 1:3], cols = NULL, rows=NULL, theme=ttheme_default(base_size=7))
g2$heights <- g3$heights <- unit(rep(1/nrow(g2), nrow(g2)), "npc")
grid.arrange(rectGrob(), rectGrob(), rectGrob(), nrow=1, newpage = FALSE)
grid.arrange(g, g2, g3, nrow=1, newpage = FALSE)
If the page size can be changed, it is usually the best option. One can query the table size before drawing, convert it to inches, and pass it to the device.
g1 <- tableGrob(iris[1:4, 1:5])
g2 <- tableGrob(iris[1:20, 1:5])
maxheight <- convertHeight(sum(g2$heights), "in", TRUE)
pdf("fit.pdf", height=maxheight)
grid.draw(g1)
grid.newpage()
grid.draw(g2)
dev.off()
However, as far as I know all pages in a given pdf will have to have the same size (there might be ways around it, but tricky).

R: background or inserted image and text in lattice

I'd like to insert a watermark onto a lattice image. In ggplot2, I simply used the the annotate or annotation_custom options to place a logo image and a text below the logo in a corner of the plot. Is there a similar possibility in lattice? Or as an alternative - is it possible to use an image as background of the plot?
This is what Deepayan Sarkar offered on Rhelp a couple of years ago to a similar question:
barchart(variety ~ yield | site, data = barley, groups = year, layout = c(3,1),
page = function(n) {
grid.text(label = "Privileged and Confidential \nDRAFT",
x = unit(0.01, "npc"),
y = unit(0.95, "npc"),
just = c("left", "center")) })
Obviously you would also need to use grid graphics functions to place the logo, (but you haven't offered one to work with. The first two lines of this next code was found at #baptiste's blog page cited today on SO.) The second two lines were adapted from Paul Murrell's article in last years "R Journal" found with Rseek.org:
library(png)
m <- readPNG(system.file("img", "Rlogo.png", package="png"), FALSE)
rimg <- as.raster(m)
grid.raster(rimg, x=.05, y=.9, just="top", width=.1)

How to put two 'vcd' grid graphics in a single plot?

I would like to place two (somewhat non-standard) grid graphics in a single plot in R.
Try:
require(vcd)
mosaic(Titanic)
assoc(Titanic)
The trouble is that these aren't lattice graphics, and to my knowledge do not come with a layout argument or similar. And since these are grid graphs, they're impervious to base graph tricks like par(mfrow=c(1,2)).
How can I place the two graphs above in a single plot, with both graphs on the same line?
I already tried the suggestions in How to plot grid plots on a same page?, but they don't seem to work for vcd plots. Ultimately I would like to obtain something similar to:
Neither plot seems to return any object and I cant see how to grab the grobs from looking at grid.ls(). So using the idea from this answer
library(vcd)
library(gridGraphics)
library(gridExtra)
mosaic(Titanic)
m <- grid.grab()
assoc(Titanic)
a <- grid.grab()
grid.newpage()
grid.arrange(m, a, ncol=2)
Im sure there will be a more grid-like approach but ...
Something similar to the solution in How to plot grid plots on a same page? can also be used for vcd displays. The difference is that you need to set newpage = FALSE (to prevent opening a new display) and you need to push and pop the viewport yourself (which can be handy when re-using vcd graphics in more complicated displays such as partykit trees).
The mosaic and association display for the Titanic data can be visualized as:
grid.newpage()
pushViewport(viewport(layout = grid.layout(1, 2)))
pushViewport(viewport(layout.pos.col = 1, layout.pos.row = 1))
mosaic(Titanic, newpage = FALSE)
popViewport()
pushViewport(viewport(layout.pos.row = 1, layout.pos.col = 2))
assoc(Titanic, newpage = FALSE)
popViewport()
yielding
Another option is vcd’s mplot() function (for details, see ?vcd::mplot):
library(vcd)
mplot(
mosaic(Titanic, return_grob = TRUE),
assoc(Titanic, return_grob = TRUE),
keep_aspect_ratio = FALSE
)

Resources