I would like to export a data frame as a (png) image. I've tried with this code, but the table get clipped vertically.
library(ggplot2)
library(gridExtra)
df <- data.frame(a=1:30, b=1:30)
png("test.png")
p<-tableGrob(df)
grid.arrange(p)
dev.off()
Is there a way to avoid this behaviour without having to set manually the size of the image?
You can change this behavior by specifying a height and width.
png("test.png", height=1000, width=200)
p<-tableGrob(df)
grid.arrange(p)
dev.off()
Anyway, it is usually not very helpful to save tables as pictures.
You can do like this:
library(gridExtra)
png("test.png", height = 50*nrow(df), width = 200*ncol(df))
grid.table(df)
dev.off()
This works just fine:
library(gridExtra)
df = data.frame("variables" = c("d_agr","d_def","d_frig","d_hidro","d_roads","d_silos"),
"coeficient" = c(0.18,0.19,-0.01,-0.25,-0.17,0.09))
png("output.png", width=480,height=480,bg = "white")
grid.table(df)
dev.off()
To get the size of the table you have to generate a tableGrob first, than you can get the height and width parameters. The parameters are "grobwidth", they have to be converted into inch.
Here is my solution (base on gridExtra vignettes), it works fine for me.
library(grid)
library(gridExtra)
gridFtable <- function(d, pd = 4, fontsize = 10, fontfamily = "PT Mono") {
## set plot theme
t1 <- ttheme_default(padding = unit(c(pd, pd), "mm"), base_size = fontsize, base_family = fontfamily)
## character table with added row and column names
extended_matrix <- cbind(c("", rownames(d)), rbind(colnames(d), as.matrix(d)))
## get grob values
g <- tableGrob(extended_matrix, theme = t1)
## convert widths from grobwidth to inch
widthsIn <- lapply(g$widths, function(x) {convertUnit(x, unitTo = "inch", valueOnly = TRUE)})
heigthsIn <- lapply(g$heights, function(x) {convertUnit(x, unitTo = "inch", valueOnly = TRUE)})
## calculate width and height of the table
w <- sum(unlist(widthsIn)) - 1*convertUnit(unit(pd, "mm"), unitTo = "inch", valueOnly = TRUE)
h <- sum(unlist(heigthsIn)) - 1*convertUnit(unit(pd, "mm"), unitTo = "inch", valueOnly = TRUE)
return(list(grobData = g, data = d, width = w, heigth = h, theme = t1))
}
saveTable <- gridFtable(data.frame(a=1:30, b=1:30))
png(file = "./test.png", width = saveTable$width, height = saveTable$heigth, units = "in", res = 100)
grid.newpage()
grid.table(saveTable$data, rows = NULL, theme = saveTable$theme)
dev.off()
getwd()
Related
I'm new to grobbing and I am trying to create a simple grid.arrange object but cannot figure out how to might a compact/tight layout.
Below is a simple example of what I'm trying to run and the grob that I get.
library(grid)
library(gridExtra)
name = textGrob("My Name", gp=gpar(fontsize = 20, fontface = "bold"))
name2 = textGrob("Second Name", gp=gpar(fontsize = 16))
tbl = tableGrob(head(iris))
grid.arrange(name, name2, tbl)
UPDATE:
Using the answer found here I was able to get the text compact but I am still struggling to get the table to be right under the text.
library(grid)
library(gridExtra)
name = textGrob("My Name", gp=gpar(fontsize = 20, fontface = "bold"))
name2 = textGrob("Second Name", gp=gpar(fontsize = 16))
tbl = tableGrob(head(iris))
margin = unit(0.5, "line")
grid.newpage()
grid.arrange(name, name2, tbl,
heights = unit.c(grobHeight(name) + 1.2*margin,
grobHeight(name2) + margin,
unit(1,"null")))
Typically you'd use the top= argument for a single grob. With two grobs like this, it might be easiest to combine them in a table; the major hurdle is that gtable doesn't consider justification so you have to adjust the positions yourself,
library(gtable)
justify <- function(x, hjust="center", vjust="top", draw=FALSE){
w <- sum(x$widths)
h <- sum(x$heights)
xj <- switch(hjust,
center = 0.5,
left = 0.5*w,
right=unit(1,"npc") - 0.5*w)
yj <- switch(vjust,
center = 0.5,
bottom = 0.5*h,
top=unit(1,"npc") - 0.5*h)
x$vp <- viewport(x=xj, y=yj)
if(draw) grid.draw(x)
return(x)
}
title <- gtable_col('title', grobs = list(name,name2),
heights = unit.c(grobHeight(name) + 1.2*margin,
grobHeight(name2) + margin))
grid.newpage()
grid.arrange(justify(title, vjust='bottom'), justify(tbl))
I was running the example here, and noticed that the horizontal arrow connecting the Total to the Ineligible boxGrobs doesn't always touch the left-edge of the the Ineligible boxGrob.
It seems to depend on the width of the viewing window in RStudio. This does not seem to be the case for the vertical arrow, which always seem to perfectly connect to the top of the correct boxGrob.
Is there a way to force the arrow to touch the side of the box and not go any further? I am trying to save the output to a pdf, and by default it seems to use a wider plotting window so all of my horizontal arrows don't align with the correct boxes.
Narrow plotting window:
Wide plotting window:
I have tried manually creating a viewport with a wider area, but that didn't change anything in the pdf:
Code:
library(grid)
library(Gmisc)
vp <- grid::viewport(x = 10, y = 10, clip = 'on', xscale = c(0, 10),
yscale = c(0, 10), default.units = 'inch')
grid::pushViewport(vp)
leftx <- .25
midx <- .5
rightx <- .75
width <- .4
gp <- gpar(fill = "lightgrey")
# add box/connectors to the plot
(total <- boxGrob("Total\n N = NNN",
x=midx, y=.9, box_gp = gp, width = width))
(rando <- boxGrob("Randomized\n N = NNN",
x=midx, y=.75, box_gp = gp, width = width))
connectGrob(total, rando, "v")
(inel <- boxGrob("Ineligible\n N = NNN",
x=rightx, y=.825, box_gp = gp, width = .25, height = .05))
connectGrob(total, inel, "-")
For the time being, this problem can be solved using absolute unit.
Example code:
(inel <- boxGrob("Ineligible\n N = NNN",
x=rightx, y=.825, box_gp = gp, width = unit(2, "inch"), height = .05))
i am creating overlapping labels in a textGrob
txt <- rep("Hi there",2)
grid.newpage()
fg <- frameGrob()
tg <- textGrob(label = txt,x = c(0.25,0.4),y=c(0.5,0.5))
fg <- packGrob(fg, tg)
grid.draw(fg)
then i take the same textGrob and find the text bounds, convertUnit and draw the tight boxes around the text and plot again i get boxes that dont overlap.
What is the correct way to define tg_bounds in order to reproduce the overlap?
tg_bounds <- function(tg,lab,theta){
bounds <- grid:::grid.Call(grid:::L_textBounds,
grDevices::as.graphicsAnnot(tg$label[lab]),
tg$x[lab],
tg$y[lab],
resolveHJust(tg$just, tg$hjust),
resolveVJust(tg$just,tg$vjust),
tg$rot, theta)
bounds <- unit(bounds, "inches")
convertUnit(bounds,unitTo = attr(tg$x,'unit'),valueOnly = TRUE)
}
bounds1 <- do.call('rbind',lapply(seq(1,360,1),tg_bounds,tg = tg,lab = 1))
bounds2 <- do.call('rbind',lapply(seq(1,360,1),tg_bounds,tg = tg,lab = 2))
plot(bounds1[,1],bounds1[,2],type='line',xlim = c(0,.5),ylim = c(0.4,.5))
lines(bounds2[,1],bounds2[,2])
I have recently started using the grid.table function from the gridExtra package to turn tabular data into png image files for use on the web. I've been delighted with it so far as it produces very good-looking output by default, sort of like a ggplot2 for tables. Like the person who asked this question I would love to see the ability to specify the justification for individual columns but that would be icing on what is an already more-ish cake.
My question is whether it is possible to add text around a grid.table so that I can give plotted tables a title and a footnote. It seems to me this should be feasible, but I don't know enough about grid graphics to be able to work out how to add grobs to the table grob. For example, this code:
require(gridExtra)
mydf <- data.frame(Item = c('Item 1','Item 2','Item 3'),
Value = c(10,15,20), check.names = FALSE)
grid.table(mydf,
gpar.coretext=gpar(fontsize = 16),
gpar.coltext = gpar(fontsize = 16),
gpar.rowtext = gpar(fontsize = 16),
gpar.corefill = gpar(fill = "blue", alpha = 0.5, col = NA),
h.even.alpha = 0.5,
equal.width = FALSE,
show.rownames = FALSE,
show.vlines = TRUE,
padding.h = unit(15, "mm"),
padding.v = unit(8, "mm")
)
generates this plot:
when I would really like to be able to do something like the following in code rather than by editing the image with another application:
To place text close to the table you'll want to evaluate the table size first,
library(gridExtra)
d <- head(iris)
table <- tableGrob(d)
grid.newpage()
h <- grobHeight(table)
w <- grobWidth(table)
title <- textGrob("Title", y=unit(0.5,"npc") + 0.5*h,
vjust=0, gp=gpar(fontsize=20))
footnote <- textGrob("footnote",
x=unit(0.5,"npc") - 0.5*w,
y=unit(0.5,"npc") - 0.5*h,
vjust=1, hjust=0,gp=gpar( fontface="italic"))
gt <- gTree(children=gList(table, title, footnote))
grid.draw(gt)
Edit (17/07/2015) With gridExtra >=2.0.0, this approach is no longer suitable. tableGrob now returns a gtable, which can be more easily customised.
library(gridExtra)
d <- head(iris)
table <- tableGrob(d)
library(grid)
library(gtable)
title <- textGrob("Title",gp=gpar(fontsize=50))
footnote <- textGrob("footnote", x=0, hjust=0,
gp=gpar( fontface="italic"))
padding <- unit(0.5,"line")
table <- gtable_add_rows(table,
heights = grobHeight(title) + padding,
pos = 0)
table <- gtable_add_rows(table,
heights = grobHeight(footnote)+ padding)
table <- gtable_add_grob(table, list(title, footnote),
t=c(1, nrow(table)), l=c(1,2),
r=ncol(table))
grid.newpage()
grid.draw(table)
If you want just the title (no footnote), here is a simplified version of #baptiste's example:
title <- textGrob("Title", gp = gpar(fontsize = 50))
padding <- unit(0.5,"line")
table <- gtable_add_rows(
table, heights = grobHeight(title) + padding, pos = 0
)
table <- gtable_add_grob(
table, list(title),
t = 1, l = 1, r = ncol(table)
)
grid.newpage()
grid.draw(table)
I am trying to make figures for a manuscript, that should be written with MS Word, which does not accept figures in pdf format. The journal asks first draft with figures embedded in the Word file. These figures should have resolution minimum of 300 dpi and have a width of either 169 mm or 81 mm (two/one column). I notice that when I specify the resolution of the picture to 300 (res = 300), the font size is bound to this value. This works fine with some figures (the first example, example.png), and worse with others (example2.png). How can I control the font size so that the dimensions and resolution of the figure remain fixed?
library(ggplot2)
library(grid)
data(iris)
vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y)
p <- ggplot(iris, aes(Species, Petal.Length))
q <- ggplot(iris, aes(Species, Petal.Width))
len <- p + geom_boxplot()
wid <- q + geom_boxplot()
png("example.png", width = 169, height = 100, units = "mm", res = 300)
grid.newpage()
pushViewport(viewport(layout = grid.layout(1, 2)))
print(len, vp = vplayout(1, 1))
print(wid, vp = vplayout(1, 2))
dev.off()
png("example2.png", width = 81, height = 100, units = "mm", res = 300)
grid.newpage()
pushViewport(viewport(layout = grid.layout(1, 2)))
print(len, vp = vplayout(1, 1))
print(wid, vp = vplayout(1, 2))
dev.off()
In other words, I would like to decrease the font size in example2.png, but keep the layout and dimensions of the two plots as they are.
Example.png
Example2.png
Using the base_size argument to the theme_XXX() function, you can change the overall font sizes for all the text.
png("example2.png", width = 81, height = 100, units = "mm", res = 300)
grid.newpage()
pushViewport(viewport(layout = grid.layout(1, 2)))
print(len + theme_gray(base_size=12*(81/169)), vp = vplayout(1, 1))
print(wid + theme_gray(base_size=12*(81/169)), vp = vplayout(1, 2))
dev.off()
Simply change the pointsize attribute of png. For example:
png(filename="plot4.png", width=580, height=700, pointsize=20)
As far as I can tell the fontsize is the same regardless of the resolution and device size. You can check it in the following examples:
library(grid)
png("example1.png", width = 30, height = 5, units = "mm", res = 200)
g <- grid.text("testing font size", gp=gpar(fontsize=12))
width <- convertUnit(grobWidth(g), "mm")
height <- convertUnit(grobHeight(g), "mm", "y")
grid.rect(width=width, height=height, gp=gpar(lty=2, fill=NA))
dev.off()
png("example2.png", width = 60, height = 5, units = "mm", res = 500)
grid.text("testing font size", gp=gpar(fontsize=12))
grid.rect(width=width, height=height, gp=gpar(lty=2, fill=NA))
dev.off()
But it seems you actually wanted to change the font size.