saving multiple ggplots WITHOUT for loop - r

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)

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])
})

imap() - return results in list in R

Most of the included code serves reproducibility,my question is regarding the export of results from an imap() function.
I have written some functions that aggregate and summarize my data, as below. It creates a list, with multiple lists - one list for every gears.
splitCars <- split(mtcars, mtcars$cyl)
summarizeMtcarsYearly <- function(x)
{
#Ngears
v1 <- length(unique(x$gear))
v2 <- paste0(unique(levels(as.factor(x$gear))),collapse = ', ')
#Build data
y <- data.frame(Ngears=v1,gears=v2,stringsAsFactors = F)
return(y)
}
summarizeMtcars <-function(){
splitCars <- split(mtcars, mtcars$cyl)
splitCars <- lapply(splitCars,summarizeMtcarsYearly)
}
splitCars <- summarizeMtcars()
for every gear in the list, i want to create the summary table. I have also written a function for this (below). The details are not important, this is just for reproducibility. The important part of this function is where I export the table to a results folder - last 5 lines.
createSummaryTable <- function(x, y){
tab <- plot_ly(
type = 'table',
header = list(
values = c(paste0("Gears = "), y, ""),
align = c('left', rep('center')),
line = list(width = 1, color = 'black'),
fill = list(color = 'rgb(235, 100, 230)'),
font = list(family = "Arial", size = 14, color = "white")
),
cells = list(
values = rbind(c('number of gears', 'list of gears'),
c(x$Ngears, x$gears)),
align = c('left', rep('center')),
line = list(color = "black", width = 1),
fill = list(color = c('rgb(235, 193, 238)', 'rgba(228, 222, 249, 0.65)')),
font = list(family = "Arial", size = 12, color = c("black"))
))
test_dir <- "/Users/testFolder"
tab <- plotly_json(tab, FALSE)
tabName <- paste0("summaryVariables_gear_TEST", y, ".json" )
write(tab, paste0(test_dir, "/", tabName))
}
I pretend not to know how many gears my data will have i am then using imap() function to apply a createSummaryTable to every element of the list, and exported it directly to a predefined folder:
splitCars <- summarizeMtcars()
imap(splitCars, function(x, y) createSummaryTable(x,y))
which was working exactly the way i wanted to have it. However, now, i need to return all the tables for every single gear inside a list, something like this:
createSummaryTable <- function(x, y){
tab <- ... # this is the same as before
tabname <- paste0("summary_", y)
assign(tabname, tab)
}
analysis.summaryTables <- function(){
# create tables
splitCars <- summarizeMtcars()
imap(splitCars, function(x, y) createSummaryTable(x,y))
# append all tables to one list
tables <- ls(patter = "summary_")
out <- do.call(c,list(tables))
}
however when i run this
summaryTables <- analysis.summaryTables()
summaryTable is just an empty character string.
How can i store all the output from imap() in a single list in R ??
how can i access the elements from the function createSummaryTable environment and append them together in R?
If I understood correctly, you have a function createSummaryTable that creates an object, a table to be specific.
You have a list of named dataframe and you want to map this list into your function to return a list of objects (a list of tables to be specific) where their names will be the same but "summary_" has to appear before.
Therefore:
createSummaryTable <- function(x, y){
# do something here
return(tbl)
}
# map your list
out <- purrr::imap(list_of_named_dataframes, createSummaryTable)
names(out) <- paste("summary", names(out), sep = "_")
and out is what you're looking for.

How to Save as png with ChartJSRadar in R?

I'm trying to save my plot with resolution of 300 for publication purposes. The usual methods to save plots with png device isn't working and saves a blank png. Is there something else I can try, or a different package that does something similar?
library(radarchart)
data<-data.frame(Field=c("Age","Sex","Submission"), y=sample(1:100,3), x=sample(1:100,3))
path<-"C:\\Desktop\\R\\"
png(file=paste0(path,"Radar",".png"), width=500, height=500, res=300)
plot<-chartJSRadar(scores=data, labelSize= 10, main="Completeness Radar", maxScale = 100)
print(plot)
dev.off()
I've also tried:
png(file=paste0(path,"Radar",".png"), width=500, height=500, res=300)
chartJSRadar(scores=data, labelSize= 10, main="Completeness Radar", maxScale = 100)
dev.off()
library(radarchart)
library(webshot)
library(htmlwidgets)
dat <- data.frame(
Field = c("Age","Sex","Submission"),
y = sample(1:100,3),
x = sample(1:100,3)
)
plt <- chartJSRadar(
scores = dat,
labelSize= 10,
main="Completeness Radar",
maxScale = 100
)
saveWidget(plt, "plt.html")
webshot("plt.html")
magick::image_read("webshot.png")
radar charts are very difficult for folks to grok
data and plot are suberbad variable names
whitespace is your bff
webshot can limit target area
various magick ƒ()s can crop target area
consider using http://www.ggplot2-exts.org/ggradar.html

Saving multiply pdf plots r

I have made a loop for making multiply plots, however i have no way of saving them, my code looks like this:
#----------------------------------------------------------------------------------------#
# RING data: Mikkel
#----------------------------------------------------------------------------------------#
# Set working directory
setwd()
#### Read data & Converting factors ####
dat <- read.table("Complete RING.txt", header =TRUE)
str(dat)
dat$Vial <- as.factor(dat$Vial)
dat$Line <- as.factor(dat$Line)
dat$Fly <- as.factor(dat$Fly)
dat$Temp <- as.factor(dat$Temp)
str(dat)
datSUM <- summaryBy(X0.5_sec+X1_sec+X1.5_sec+X2_sec+X2.5_sec+X3_sec~Vial_nr+Concentration+Sex+Line+Vial+Temp,data=dat, FUN=sum)
fl<-levels(datSUM$Line)
colors = c("#e41a1c", "#377eb8", "#4daf4a", "#984ea3")
meltet <- melt(datSUM, id=c("Concentration","Sex","Line","Vial", "Temp", "Vial_nr"))
levels(meltet$variable) <- c('0,5 sec', '1 sec', '1,5 sec', '2 sec', '2,5 sec', '3 sec')
meltet20 <- subset(meltet, Line=="20")
meltet20$variable <- as.factor(meltet20$variable)
AllConcentrations <- levels(meltet20$Concentration)
for (i in AllConcentrations) {
meltet.i <- meltet20[meltet20$Concentration ==i,]
quartz()
print(dotplot(value~variable|Temp, group=Sex, data = meltet.i ,xlab="Time", ylab="Total height pr vial [mm above buttom]", main=paste('Line 20 concentration ', meltet.i$Concentration[1]),
key = list(points = list(col = colors[1:2], pch = c(1, 2)),
text = list(c("Female", "Male")),
space = "top"), col = colors, pch =c(1, 2))) }
I have tried with the quartz.save function, but that just overwrites the files. Im using a mac if that makes any difference.
When I want to save multiple plots in a loop I tend to do something like...
for(i in AllConcentrations){
meltet.i <- meltet20[meltet20$Concentration ==i,]
pdf(paste("my_filename", i, ".pdf", sep = ""))
dotplot(value~variable|Temp, group=Sex, data = meltet.i ,xlab="Time", ylab="Total height pr vial [mm above buttom]", main=paste('Line 20 concentration ', meltet.i$Concentration[1]),
key = list(points = list(col = colors[1:2], pch = c(1, 2)),
text = list(c("Female", "Male")),
space = "top"), col = colors, pch =c(1, 2))
dev.off()
}
This will create a pdf file for every level in AllConcentrations and save it in your working directory. It will paste together my_filename, the number of the iteration i, and then .pdf together to make each file unique. Of course, you will want to adjust height and width in the pdf function.

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