Save 2-plot figures in pdf within for loop - r

I have multiple plots to save as .pdf files and they are created in R by using par(mfrow=c(1,2)), i.e. per each figure (to be saved) there are 2 plots disposed by 1 row and 2 columns.
Since my total number of plots is quite high I am creating the plots with a for loop.
How can I save the figures (with 2 plots each one) as pdf files in the for loop?
Here's same funky code:
## create data.frames
df_1 = data.frame(x = c(1:100), y = rnorm(100))
df_2 = data.frame(x = c(1:100), y = rnorm(100))
df_3 = data.frame(x = c(1:100), y = rnorm(100))
df_4 = data.frame(x = c(1:100), y = rnorm(100))
## create list of data.frames
df_lst = list(df_1, df_2, df_3, df_4)
## plot in for loop by 1 row and 2 cols
par(mar=c(3,3,1,0), mfrow=c(1,2))
for (i in 1:length(df_lst)) {
barplot(df_lst[[i]]$y)
}
Let's say I want to save the plots with the pdf function. Here's what I tried:
for (i in 1:length(df_lst)) {
pdf(paste('my/directory/file_Name_', i, '.pdf', sep = ''), height = 6, width = 12)
barplot(df_lst[[i]]$y)
dev.off()
}
My solution is clearly wrong because the pdf function saves a figure at each loop (i.e. 4 instead of 2).
Any suggestion?
Thanks

Sounds like you could use a nested loop here: an outer loop for each file you create, and an inner loop for each multi-panel figure you create. Since all the data frames are stored in a 1-d list, you'll then need to keep track of the index of the list that you are plotting.
Here's one way to do that:
nrow <- 1
ncol <- 2
n_panels <- nrow * ncol
n_files <- length(df_lst) / n_panels
for (i in seq_len(n_files)) {
file <- paste0("file_", i, ".pdf")
pdf(file, height = 6, width = 12)
# plot params need to be set for each device
par(mar = c(3, 3, 1, 0), mfrow = c(nrow, ncol))
for (j in seq_len(n_panels)) {
idx <- (i - 1) * n_panels + j
barplot(df_lst[[idx]]$y)
}
# updated to also add a legend
legend("bottom", legend = "Bar", fill = "grey")
dev.off()
}
If you just want one file with multiple pages, all you need to do is move the pdf() call outside your original loop, and move the parameter setting after the pdf():
pdf('my/directory/file_Name.pdf', height = 6, width = 12)
par(mar=c(3,3,1,0), mfrow=c(1,2))
for (i in 1:length(df_lst)) {
barplot(df_lst[[i]]$y)
}
dev.off()

Related

ggarrange generates an empty pdf file

I am dealing with a function that takes a big data frame (36 rows and 194 columns) which performs a Principal Component Analysis and then generates a list of plots where I have the combination of 26 Principal Components which are 325 in total, using 'expand.grid'.
My problem is that when I am using ggarrange(), from ggpubr, to merge all the plots in only one pdf file, this file is empty.
My code:
a = 26
row.pairs = 325
PC.Graph <- function(df, col1, col2, tag, id){
df1 <- df[,-c(col1:col2)]
pca <- prcomp(df1, scale. = T)
pc.summ <- summary(pca)
a <- sum(pc.summ$importance[3,] < 0.975)
b <- c(1:a)
pc.grid <- expand.grid(b, b)
pc.pairs <- pc.grid[pc.grid$Var1 < pc.grid$Var2,]
row.pairs <- nrow(pc.pairs)
components <- c(1:row.pairs)
S.apply.FUN <- function(x){
c <- sapply(pc.pairs, "[", x, simplify = F)
pcx <- c$Var1
pcy <- c$Var2
df2 <- df
row.names(df2) <- df[, tag]
name = paste("PCA_", pcx, "_vs_", pcy)
autoplot(pca, data = df2, colour = id, label = T, label.repel = T, main = name,
x = pcx, y = pcy)
}
all.plots <- Map(S.apply.FUN, components)
pdf(file = "All_PC.pdf", width = 50, height = 70)
print(ggarrange(all.plots))
dev.off()
}
PC.Graph(Final_DF, col1 = 1, col2 = 5, tag = "Sample", id = "Maturation")
You would have to pass a plotlist to ggarrange, but I am not sure you would get any useful plot out of that plot area in the PDF file, so I would advise you to split the plotlist into chunks (e.g. of 20) and plot these to multiple pages.
Specifically, I would export all.plots from your PC.Graph function (and remove the code to write to PDF there).
I would also change the expand.grid(b, b) to t(combn(b, 2)), since you don't need to plot the PC combinations twice.
Then I would do something like this:
# export the full list of plots
plots <- PC.Graph(Final_DF, col1 = 1, col2 = 5, tag = "Sample", id = "Maturation")
# split the plotlist
splitPlots <- split(plots, ceiling(seq_along(plots)/20))
plotPlots <- function(x){
out <- cowplot::plot_grid(plotlist = x, ncol = 5, nrow = 4)
plot(out)
}
pdf(file = "All_PC.pdf", width = 50, height = 45)
lapply(splitPlots, plotPlots)
dev.off()

Loop set a list of command for different variables in R?

I've just studied in R programming. I'm trying to create an automatic calculation for my data, but as a newcomer, i've found it so much more difficult than i though. I hope someone help me figure this out.
My data consist of dataset of 11 species in different Csv files in the same folder. I need to run a set of command to get the graphs. For each species, i need to type again commands (From glm...to the end).
>setwd("C:\Users\OneDrive\Work\Journal Articles\I9-2019\Reports\LM50")
>library(FSA)
>temp = list.files(pattern="*.csv")
for (i in 1:length(temp)) assign(temp[i], read.table(temp[i],header=T,sep=";"))
>lr<-function(cf,p)(log(p/(1-p))-cf[1])/cf[2]
>glmFencr<-glm(Maturity~FL,data=`Encrasicholina heteroloba F 2019 TNB I9.csv`,family=binomial)
>(L50Fencr<-lr(coef(glmFencr),0.5))
> '**First result**
>fitPlot(glmFencr,xlab="FL (mm)",ylab="Percentage (%)",main="",xlim=c(0,180),plot.p=FALSE)
>lines(c(0,L50Fencr),c(0.5,0.5),lty=3,lwd=2,col="black")
>lines(c(L50Fencr,L50Fencr),c(-0.2,0.5),lty=3,lwd=2,col="black")
>**second result (graph)**
So does it possible to create a loopset for this one?
Thank you in advance!~
You could simply store your data frames in a list and loop through them. Notice it helps a lot to have your code indented and properly spaced.
library(FSA)
setwd("C:\Users\OneDrive\Work\Journal Articles\I9-2019\Reports\LM50")
lr <- function(cf, p)
{
return((log(p/(1-p))-cf[1])/cf[2])
}
all_files <- list.files(pattern="*.csv")
# Use lapply to get all your data frames and models into lists
all_data <- lapply(all_files, function(x) read.table(x, header = T, sep = ";"))
all_models <- lapply(all_data, function(x) glm(Maturity ~ FL, data = x, family = binomial))
# Now you can get your L50s as a vector
all_L50s <- unlist(lapply(all_models, function(x) lr(coef(x), 0.5)))
# Now you can loop quite easily
for(i in seq_along(all_models))
{
fitPlot(all_models[[i]], xlim=c(0, 180), plot.p = FALSE,
xlab = "FL (mm)", ylab = "Percentage(%)", main = "")
lines(c(0, all_L50s[i]), c(0.5, 0.5), lty = 3, lwd = 2, col = "black")
lines(c(all_L50s[i], all_L50s[i]), c(-0.2, 0.5), lty = 3, lwd = 2, col = "black")
}
Put the code that you want to apply to each file in a function
library(FSA)
lr <- function(cf,p)(log(p/(1-p))-cf[1])/cf[2]
apply_fun <- function(data) {
glmFencr <- glm(Maturity~FL,data=data,family=binomial)
L50Fencr <- lr(coef(glmFencr),0.5)
fitPlot(glmFencr,xlab="FL (mm)", ylab="Percentage (%)",
main="", xlim=c(0,180), plot.p=FALSE)
lines(c(0,L50Fencr),c(0.5,0.5),lty=3,lwd=2,col="black")
lines(c(L50Fencr,L50Fencr),c(-0.2,0.5),lty=3,lwd=2,col="black")
}
Get all the files and apply the function to each file using lapply. Store the output in out_plot.
temp = list.files(pattern="*.csv")
out_plot <- lapply(temp, function(x) {
df <- read.table(x, header=T,sep=";")
apply_fun(df)
})

How export several graphics from R [duplicate]

This question already has answers here:
Save ggplot within a function
(2 answers)
Closed 5 years ago.
I have list of data frames and i want to export one bar chart per data frame... I am trying use lapply but it does not work... Does anyone know how to do this?
my_data <- lapply(X = seq(from = 1, to = length(in_files_path), by = 1), FUN = function(x){
data_tables <- read.table(file = in_files_path[[x]], header = TRUE)
})
lapply(X = seq(from = 1, to = length(in_files_path), by = 1), FUN = function(x){
setwd(dir = ou_graph_path)
png(filename = in_files_name[[x]],
units = "in",
width = 15,
height = 10,
res = 300)
ggplot(data = my_data[[x]], aes(x = my_data[[x]]$A, y = my_data[[x]]$B)) +
geom_bar()
dev.off()
})
I would advice using the following approach
I would advice using the following approach
# Get list of files
# Start loop -
# read files
# make plot
# store plots in list
# - end loop
#
# Start loop -
# perform plot operation
# save plots
# - end loop
setwd(your_location_of_the_files)
list_files = list.files(pattern = ".csv")
for(i_file in list_files){
dummy = fread(i_file,header = TRUE)
png(filename = paste(your_location_for_the_plots,in_files_name[[x]],sep="/"),
units = "in",
width = 15,
height = 10,
res = 300)
# You can just say A here, not dummy$A
plot(ggplot(data = dummy, aes(x = A, y = B)) + geom_bar())
dev.off()
}

SAVE groups clustering to out of r

I wrote the follow code to clustering data :
clusrer.data <- function(data,n) {
miRNA.exp.cluster <- scale(t(miRNA.exp))
k.means.fit <- kmeans(miRNA.exp.cluster,n)
#i try to save the results of k-means cluster by this code :
k.means.fit <- as.data.frame(k.means.fit)
write.csv(k.means.fit, file="k-meanReslut.csv")
#x<-k.means.fit$clusters
#write.csv(x, file="k-meanReslut.csv")
}
but I can not save the clusters to outside of (clusters) (8, 6, 7, 20, 18), I want to save each cluster separated (with columns and rows) in txt file or CSV.
Here is one approach of splitting the original dataset according to cluster and saving that chunk to a file. I added cluster assignment to the original dataset for easier visual check. Example is partly taken from ?kmeans. Feel free to adapt the way files are written, as well as the way file name is created.
x <- rbind(matrix(rnorm(100, sd = 0.3), ncol = 2),
matrix(rnorm(100, mean = 1, sd = 0.3), ncol = 2))
colnames(x) <- c("x", "y")
(cl <- kmeans(x, 2))
x <- cbind(x, cluster = cl$cluster)
by(x, INDICES = cl$cluster, FUN = function(sp) {
write.table(sp, file = paste0("file", unique(sp$cluster), ".txt"),
row.names = TRUE, col.names = TRUE)
})

How do I concatenate one word with all elements of a list in R barplot title?

This is the code I'm currently running:
n <- 7
N <- 52
r <- 13
reps <- 1000000
deck <- rep(c('h','d','c','s'), each = r)
diamonds <- rep(NA, length.out = reps)
pos <- sample(x = 1:52, size = 7, replace = FALSE)
for(i in 1:reps) {
hand <- sample(x = deck, replace = FALSE)[pos]
diamonds[i] <- sum(ifelse(hand == 'd', 1, 0))
}
barplot(table(diamonds), col = 'red', xlab = '# of diamonds',
ylab = paste('frequency out of',reps,'trials'),
main = paste('Positions:',pos[1],pos[2],pos[3],pos[4],
pos[5],pos[6],pos[7]))
What I'd really like is to be able to give a title to the barplot with something like the following
barplot(..., main = paste('Positions:',pos))
and have the title say "Positions: p1 p2 p3 p4 p5 p6 p7", where p1,p2,...,p7 are the elements of pos.
For anyone that's interested, this code randomly chooses 7 positions from 52 and then counts the number of diamonds ('d') within those 7 positions after each shuffle of the deck for 1000000 shuffles. Then the empirical distribution of the number of diamonds within those 7 cards is plotted.
Use collapse in paste to collapse the multiple elements in a vector containing the base test and pos,
paste(c('Positions:', pos), collapse=" ")
Otherwise, when you paste "Positions:" to pos you get the former recycled to the length of pos.

Resources