Fix blank PDF pages with R - r

I am trying to generate a one file PDF with R.
I'm using pdf(), pie() and dev.off(), but all the pages in my PDF result are blank.
This is my R code:
library(jsonlite)
jsons_path <- "C:/color_uses/jsons"
setwd(jsons_path)
jsons <- list.files(jsons_path, pattern=NULL, all.files=FALSE,
full.names=FALSE)
pdf(file=paste(c("../pngs/pies.pdf"), collapse = ''), width = 1000, height = 600, onefile=T)
for(j in jsons){
color_uses <- fromJSON(j)
color_uses <- lapply(color_uses, function(x) {
x[sapply(x, is.null)] <- NA
unlist(x)
})
color_uses <- do.call("rbind", color_uses)
color_uses <- as.data.frame(color_uses)
if (is.vector(color_uses$probability)) {
color_uses$prob <- color_uses$probability
color_uses$hex <- rownames(color_uses)
color_uses <- color_uses[order(color_uses$probability),]
artist_name <- gsub(".json", "", j)
pie(color_uses$prob, col=color_uses$hex, labels=NA, main=paste(c("Colors of: ", artist_name), collapse= ''),
cex.lab=2, cex.axis=2, cex.main=2, cex.sub=2)
}
}
dev.off()
What can I do to fix the blank pages, so that I can make a pie chart on each page?

Your width and height is very high given that the units are specified as inches. The default value is 7 inches. So you should use a smaller value:
pdf(file = "path_to_your_file.pdf", width = 10, height = 6, onefile=TRUE)
# your code here
dev.off()

Related

Save/export plots from list of plots as single .png files

I'm a bit stuck on this issue. I have this data obtained from a likert survey (so I make everything a factor):
df1<-data.frame(A=c(1,2,2,3,4,5,1,1,2,3),
B=c(4,4,2,3,4,2,1,5,2,2),
C=c(3,3,3,3,4,2,5,1,2,3),
D=c(1,2,5,5,5,4,5,5,2,3),
E=c(1,4,2,3,4,2,5,1,2,3),
dummy1=c("yes","yes","no","no","no","no","yes","no","yes","yes"),
dummy2=c("high","low","low","low","high","high","high","low","low","high"))
df1[colnames(df1)] <- lapply(df1[colnames(df1)], factor)
I then create a list of dataframes to be used in each plot:
vals <- colnames(df1)[1:5]
dummies <- colnames(df1)[-(1:5)]
step1 <- lapply(dummies, function(x) df1[, c(vals, x)])
step2 <- lapply(step1, function(x) split(x, x[, 6]))
names(step2) <- dummies
tbls <- unlist(step2, recursive=FALSE)
tbls<-lapply(tbls, function(x) x[(names(x) %in% names(df1[c(1:5)]))])
This is the plotting function I made (I used the likert package)
plot_likert <- function(x){
y<-deparse(substitute(x))
y<-sub("\\$", " - ",y)
p<-plot(likert(x),
type ="bar",center=3,
group.order=names(x))+
labs(x = "Theme", subtitle=paste("Number of observations:",nrow(x)))+
guides(fill=guide_legend("Rank"))+
ggtitle(paste("How do they rank? -",gsub("\\.",": ",y)))
png(filename=paste("Ranking -",y,".png"), width = 3000, height = 2000, res=300)
print(p)
dev.off()
}
So that now I can make the plot by writing:
plot_likert(tbls$dummy1.no)
Finally, I apply the function over the whole table by using
lapply(tbls,function(x) {
y<-deparse(substitute(x))
y<-sub("\\$", " - ",y)
plot(likert(x),
type ="bar",center=3,
group.order=names(x))+
labs(x = "Theme", subtitle=paste("Number of observations:",nrow(x)))+
guides(fill=guide_legend("Rank"))+
ggtitle(paste("How do these themes rank? -",gsub("\\.",": ",y)))
}) -> list_plots
But now I don't know how to save each graph in the list as a separate .png file! I managed to put everything in a pdf like this, but it's not what I actually want:
ggsave(
filename = "plots.pdf",
plot = marrangeGrob(list_plots, nrow=1, ncol=1),
width = 15, height = 9
)
Do you have any suggestions on how to fix this? Also, if you have anything to add about my function/procedure overall, everything is welcome! I'm still quite new to R.
Thanks in advance
we can use:
sapply(1:length(list_plots), function(i) ggsave(
filename = paste0("plots ",i,".pdf"),
plot = list_plots[[i]],
width = 15, height = 9
))
For names: see https://stackoverflow.com/a/73370416/5224236
mynames <- sapply(names(tbls), function(x) {
paste("How do they rank? -",gsub("\\.",": ",x))
})
myfilenames <- names(tbls)
plot_likert <- function(x, myname, myfilename){
p <- plot(likert(x),
type ="bar",center=3,
group.order=names(x))+
labs(x = "Theme", subtitle=paste("Number of observations:",nrow(x)))+
guides(fill=guide_legend("Rank"))+
ggtitle(myname)
p
}
list_plots <- lapply(1:length(tbls),function(i) {
plot_likert(tbls[[i]], mynames[i], myfilenames[i])
})

saving multiple ggplots WITHOUT for loop

using ggsave and a for loop, I know I can save multiple ggplots onto an excel spreadsheet
For example from Save multiple ggplots using a for loop :
for (i in uniq_species) {
temp_plot = ggplot(data= subset(iris, Species == i)) +
geom_point(size=3, aes(x=Petal.Length, y=Petal.Width )) + ggtitle(i)
ggsave(temp_plot, file=paste0("plot_", i,".png"), width = 14, height = 10, units = "cm")
}
But would I would like to do is avoid the loop, as I have a list of plots.
Using lapply I have ( I presume) a list of plots:
y.plot = lapply(1:nrow(df), function(row)
{
...
}
my question is, is there a way to take y.plot from above, and shove all of the graphs in there onto one excel spreadsheet, without a loop?
something like: ggsave(pic_path,plot=y.plot,width = 20,height=20,units='cm')
but this doesn't work
Perhaps, you are looking for this
dfs <- c("cars","pressure","mtcars")
my_plots <- list()
y.plot <- list()
en <- length(dfs)
y.plot <- lapply(1:en, function(i){
df <- get(dfs[i])
varname <- colnames(df)
x=df[,1]
y=df[,2]
my_plots[[i]] <- ggplot(data=df,aes(x=x,y=y)) + geom_point() +
labs(x=varname[1], y=varname[2]) + theme_bw()
})
myplots <- do.call(grid.arrange, c(y.plot, ncol = en))
location <- "C:\\_My Work\\RStuff\\GWS\\"
ggsave(plot=myplots, file=paste0(location,"myplots.png"), width = 14, height = 10, units = "cm")
Please note that ggsave currently recognises the extensions eps/ps, tex (pictex), pdf, jpeg, tiff, png, bmp, svg and wmf (windows only).
If you wish to save it to a excel file, you need to save the image as a jpeg file and then use openxslx as shown below
ggsave(plot=myplots, file=paste0(location,"myplots.jpeg"), width = 14, height = 10, units = "cm")
pic_path <- paste0(location,"myplots.jpeg")
# Add to a new work book -------------
wb <- openxlsx::createWorkbook()
addWorksheet(wb, "Plots")
insertImage(wb, "Plots", pic_path)
openxlsx::saveWorkbook(wb, file=paste0(location,"myplots.xlsx"), overwrite = TRUE)
# Kill pic
unlink(pic_path)

Add title to PDF table in R using grid and gridExtra

I was hoping to expand on print to pdf file using grid.table in r - too many rows to fit on one page in order to add a title to the PDF
title <- "Table 1: Iris Data"
d <- iris[sample(nrow(iris), 187, TRUE),]
d$another <- "More Data"
d$column <- "Even More Will it Be off the Page"
The Provided Answer
library(gridExtra)
library(grid)
d <- iris[sample(nrow(iris), 187, TRUE),]
d$another <- "More Data"
d$column <- "Even More Will it Be off the Page"
tg <- tableGrob(d, rows = seq_len(nrow(d)))
fullheight <- convertHeight(sum(tg$heights), "cm", valueOnly = TRUE)
margin <- unit(0.51,"in")
margin_cm <- convertHeight(margin, "cm", valueOnly = TRUE)
a4height <- 29.7 - margin_cm
nrows <- nrow(tg)
npages <- ceiling(fullheight / a4height)
heights <- convertHeight(tg$heights, "cm", valueOnly = TRUE)
rows <- cut(cumsum(heights), include.lowest = FALSE,
breaks = c(0, cumsum(rep(a4height, npages))))
groups <- split(seq_len(nrows), rows)
gl <- lapply(groups, function(id) tg[id,])
pdf("multipage.pdf", paper = "a4", width = 0, height = 0)
for(page in seq_len(npages)){
grid.newpage()
grid.rect(width=unit(21,"cm") - margin,
height=unit(29.7,"cm")- margin)
grid.draw(gl[[page]])
}
## alternative to explicit loop:
## print(marrangeGrob(grobs=gl, ncol=1, nrow=1, top=NULL))
dev.off()
How can I change this code so that I can add title to the first page of the PDF?

Add multi-line footnote to tableGrob, while using gridextra in R

I have recently started using tableGrob and gridextra to combine multiple plots and tables. i want mt tableGrob to have a footnote and title.
The following link answers that nicely:
Adding text to a grid.table plot
But in the above code the footnote gets truncated it its too long. Can someone please suggest an alternative so that the footnote automatically wraps to the next line once it had reached the end of the table? If it can wrap in the middle of the word that is fine as well.
test <- data.frame(boo = c(20,1), do = c(2,10), no = c(3,5),co = c('ed','jeff'))
t1 <- tableGrob(test)
tw <- convertWidth(unit(grobWidth(t1),'npc'),
"in", valueOnly = T)
title <- textGrob("Title is long too or is it??",gp=gpar(fontsize=15))
footnote <- textGrob("footnote is pretty longgg but not unusually longgggggggggkjwd jwkldn", x=0, hjust=0,
gp=gpar( fontface="italic"))
padding <- unit(0.5,"line")
t1 <- gtable_add_rows(t1,
heights = grobHeight(title) + padding,
pos = 0)
t1 <- gtable_add_rows(t1,
heights = grobHeight(footnote)+ padding)
t1 <- gtable_add_grob(t1, list(title, footnote),
t=c(1, nrow(t1)), l=c(1,1),
r=ncol(t1))
grid.arrange(t1)
I want this to work when I have a plot and a table in grid arrange as well. Please help.
I tried using strwrap and setting the width to grobWidth but it did not work for me.
the RGraphics book/package offers a possible solution,
splitString <- function (text, width) {
strings <- strsplit(text, " ")[[1]]
newstring <- strings[1]
linewidth <- stringWidth(newstring)
gapwidth <- stringWidth(" ")
availwidth <- convertWidth(width, "in", valueOnly = TRUE)
for (i in 2:length(strings)) {
width <- stringWidth(strings[i])
if (convertWidth(linewidth + gapwidth + width, "in",
valueOnly = TRUE) < availwidth) {
sep <- " "
linewidth <- linewidth + gapwidth + width
}
else {
sep <- "\n"
linewidth <- width
}
newstring <- paste(newstring, strings[i], sep = sep)
}
newstring
}
tit <- "Title is long too or is it??"
foot <- "footnote is pretty longgg but not unusually longgggggggggkjwd jwkldn"
footnote <- textGrob(splitString(foot, sum(t1$widths)))
title <- textGrob(splitString(tit, sum(t1$widths)))
t1 <- gtable_add_rows(t1, heights = grobHeight(footnote))
t1 <- gtable_add_rows(t1, heights = grobHeight(title), 0)
t1 <- gtable_add_grob(t1, list(title, footnote),
t=c(1, nrow(t1)), l=1, r=ncol(t1))
grid.draw(t1)

vertical alignment of gridExtra tableGrob (R grid graphics/grob)

Having some trouble aligning a grid graphics object -- have read all the docs I can find, including the Murrell book, but no success. I think what I'm trying to do is pretty straightforward, so hopefully I'm missing simple.
Here's a reproducible example that will make a PDF of all the air carriers by destination in Hadley's hflights package (mirrors what I am trying to do on a different data set).
require(hflights)
require(gridExtra)
require(Cairo)
make_table <- function(df) {
p <- tableGrob(
df
,padding.h=unit(.25, "mm")
,show.rownames=FALSE
,gpar.coretext = gpar(fontsize=8, lineheight=0)
#this doesn't seem to justify the table
,just = c("bottom")
,show.box = T
)
return(p)
}
dests <- unique(hflights$Dest)
#list to hold the plots
plot_list <- list()
#loop over destinations and make a simple report
for (i in dests) {
#just this destination
this_dest <- hflights[hflights$Dest == i, ]
#the title
title <- textGrob(label = i, gp = gpar(fontsize=72, fontface = 'bold'))
#a table of carriers
carriers <- unique(this_dest$UniqueCarrier)
carriers <- data.frame(
carrier=carriers
)
carrier_table <- make_table(carriers)
#put them together
p <- arrangeGrob(
title, carrier_table
,nrow=2
)
plot_list[[i]] <- p
}
#print the report
Cairo(
width = 11, height = 8.5
,file = paste('destinations.pdf', sep = ''), type="pdf"
,units = "in"
)
print(plot_list)
dev.off()
I want the entire table produced by tableGrob (in the make_table function) to justify to the top of the grob. Right now it is centered vertically and horizontally inside the grob. Do I need to do that in the call to tableGrob, or is it in the arrangeGrob call? To ask it another way, in case the above is not clear, how can I make the whole table (not the text inside of it) justify to the top/bottom/left/right of its container?
Thanks!
try this,
library(gridExtra)
justify <- function(x, hjust="center", vjust="center", draw=TRUE){
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)
}
g <- tableGrob(iris[1:3,1:2])
grid.newpage()
justify(g,"right", "top")

Resources