Save multiple plots as individual PDFs with unique names in R - r

I have a function that creates a plot and saves it as a pdf file. I plan on running this function in a loop for 100+ columns of a dataset. My question is how to make each pdf file uniquely named so it doesnt overwrite the previous file every time a new one is made. I tried to make it work with C integer format
pdf(file = "~/PTY/Data/ROC Curves/ROC%03d.pdf", onefile = F, width = 7, height = 7)
with the intended outcome of titling each plot ROC001, ROC002... but it still overwrites each new one as ROC001.
createROC <- function(x) {
ROCtable <- createNAtable(x) #create dataset w/out NAs
x_NA <-x[!is.na(x)] #create analyte vector w/out NAs
#create ROC variable
newROC <- rocit(score = x_NA, class = ROCtable$DSM, negref = "0", method = "non")
#create pdf
pdf(file = "~/PTY/Data/ROC Curves/ROC%03d.pdf", onefile = F, width = 7, height = 7)
#create ROC plot
plot(newROC, legend = F)
dev.off()
}
My function takes a vector (data1$IL6, data1$age, etc) as an input. Ideally, I would be able to title each plot after the input (IL6, age, etc).
Thank you ahead of time for your help

The problem is that you are opening and closing the graphics device with each plot, and the counter resets at 001 each time. You need one call to pdf(), followed by all of your calls to plot(), followed by dev.off(), like so:
# Some data with named columns
df <- data.frame(a = 1:10, b = 11:20, c = 21:30)
# A plotting function without `pdf()` and `dev.off()`
create_plot <- function(x, main) {
plot(x, main = main)
}
# Open graphics device
pdf(file = "filename-%03d.pdf", onefile = FALSE)
# Apply plotting function to each column of `df` in a loop
for (j in 1:3) {
create_plot(df[, j], names(df)[j])
}
# Close graphics device
dev.off()
This should generate filename-001.pdf, filename-002.pdf, and filename-003.pdf in your working directory.

Related

How to create dynamic names for ggplot? [duplicate]

My data (TransDat70) contains 103 variables total. The first 102 are named "V1" through "V102", the last variable is names "Time.Min".
I need to generate 102 ggplots of each variable (V1 through V102) against the variable "Time.Min". I then need to save all these ggplots in a separate file (pdf) preferably all next to/below one another for comparison purposes.
I tried using code that I was able to find online but none has worked for me so far.
Here is my code:
var_list = combn(names(TransDat70)[1: 102], 2, simplify = FALSE)
plot_list = list()
for (i in 1: 3) {
p = ggplot(TransDat70, aes_string(x = var_list[[i]][1], y = var_list[[i]][2])) + geom_point()
plot_list[[i]] = p
}
for (i in 1: 3) {
plot70 = paste("iris_plot_", i, ".tiff", sep = "")
tiff(plot70)
print(plot_list[[i]])
dev.off()
}
pdf("plots.pdf")
for (i in 1: 3) {
print(plot_list[[i]])
}
dev.off()
Any suggestions?
If by separate you meant each plot in a separate file, how about this?
library(ggplot2)
# FAKE DATA AS EXAMPLE
TransDat70 <- data.frame(
1:10,
1:10,
1:10,
1:10,
1:10
)
colnames(TransDat70) <- c('V1', 'V2', 'V3', 'V4', 'Time.Min')
for (i in 1:(length(TransDat70) - 1)) {
p <- ggplot(TransDat70, aes_string(x = paste('V', toString(i), sep=''), y='Time.Min')) + geom_point()
ggsave(paste('~/Desktop/plot_', i, '.pdf', sep=''), p)
}
See the ggsave documentation for more options.
If you meant to have them all in one big file, take a look at Printing multiple ggplots into a single pdf, multiple plots per page.
However, for that many plots it would make a likely make a huge file, which could be problematic to open, especially if you have many points in your plots. In that case it might be better to compare them as separate files.

How do I convert an UTF8 encoded emoji character to an image?

I have a long vector containing emojis, something like this:
emojis <- c("😐","😥","😴","😉","😛")
and then I have their utf-8 encodings which I extracted with the help of devtools::install_github( "ThinkRstat/utf8splain") followed by library(utf8splain) like this, just for example: (not accurately represented)
emojis_enc <- c()
for(i in 1:length(emojis)){
emojis_enc <- c(emojis_enc, utf8splain::runes(emojis[i])$rune)
}
#emojis_enc <- c("U+12345","U+67891","U+91234","U+56789","U+123A6")
Then I have made a function this:
emojiPlot <- function(photo_enc, emo_char){
png(paste0(photo_enc, ".png"))
plot(emo_char, rescale = T, ylim = c(-1,1), xlim = c(-1,1))
dev.off()
}
And when I do this emojiPlot("emojis_enc[1]", emojis[1]) I just get an empty plot with x and y axis. I am pretty novice with UTF and R.
The reason why I am doing is because I am using a plugin called "imagepreview" in gephi software. And the plugin requires the nodes as photos. So my goal is to have individual emojis in .png and give them their utf encodings as the name. So when I import my data, I can just point the CSV containing the utfs to the names of the photos and pull the right emoji. And then just graph it.
I am doing this for a research project. I am open to better ways to do it.
I am in Ubuntu OS. If you use Windows, then emojis will show as their correct utf format, and won't be rendered.
Another solution to get to the png files of the emojis is to download them from Twitter, which accepts runes in the urls linking to the png files:
library(tidyverse)
data <- tibble(emojis = c("😐","😥","😴","😉","😛")) %>%
mutate(rune = map_chr(emojis, ~ utf8splain::runes(.)$rune)) %>% # convert to runes
mutate(rune = str_remove(rune, fixed("U+"))) %>% # remove leading U+
mutate(emoji_url = paste0("https://abs.twimg.com/emoji/v2/72x72/", # make url
tolower(rune), ".png"))
# download the files
map2(data$emoji_url, paste0(data$rune, ".png"), function(x, y) download.file(x, y, method = "curl"))
This will download the png files and place them in your working directory.
In base
The tidyverse code is optional, the same can be done in base:
emojis <- c("😐","😥","😴","😉","😛")
rune <- sapply(emojis, function(x) utf8splain::runes(x)$rune)
emojiurl <- paste0("https://abs.twimg.com/emoji/v2/72x72/", tolower(rune), ".png")
for (i in seq_along(emojiurl)) {
download.file(emojiurl[i], paste0(rune[i], ".png"), method = "curl")
}
You are plotting characters with plot when you should be using text.
In the code below, a plot is created with plot, argument type = "n", meaning, don't plot . Then the text (emoji) is added.
emojiPlot <- function(photo_enc, emo_char){
png(paste0(photo_enc, ".png"), units = "cm",
width = 10, height = 10, res = 600)
plot(0, 0, xlim = c(-1, 1), ylim = c(-1, 1), type = "n")
text(0, 0, emo_char)
dev.off()
}
emojiPlot("emojis_enc[1]", emojis[1])
The file "emojis_enc[1].png" is posted here:

for loop to generate and save multiple ggplots in a separate file

My data (TransDat70) contains 103 variables total. The first 102 are named "V1" through "V102", the last variable is names "Time.Min".
I need to generate 102 ggplots of each variable (V1 through V102) against the variable "Time.Min". I then need to save all these ggplots in a separate file (pdf) preferably all next to/below one another for comparison purposes.
I tried using code that I was able to find online but none has worked for me so far.
Here is my code:
var_list = combn(names(TransDat70)[1: 102], 2, simplify = FALSE)
plot_list = list()
for (i in 1: 3) {
p = ggplot(TransDat70, aes_string(x = var_list[[i]][1], y = var_list[[i]][2])) + geom_point()
plot_list[[i]] = p
}
for (i in 1: 3) {
plot70 = paste("iris_plot_", i, ".tiff", sep = "")
tiff(plot70)
print(plot_list[[i]])
dev.off()
}
pdf("plots.pdf")
for (i in 1: 3) {
print(plot_list[[i]])
}
dev.off()
Any suggestions?
If by separate you meant each plot in a separate file, how about this?
library(ggplot2)
# FAKE DATA AS EXAMPLE
TransDat70 <- data.frame(
1:10,
1:10,
1:10,
1:10,
1:10
)
colnames(TransDat70) <- c('V1', 'V2', 'V3', 'V4', 'Time.Min')
for (i in 1:(length(TransDat70) - 1)) {
p <- ggplot(TransDat70, aes_string(x = paste('V', toString(i), sep=''), y='Time.Min')) + geom_point()
ggsave(paste('~/Desktop/plot_', i, '.pdf', sep=''), p)
}
See the ggsave documentation for more options.
If you meant to have them all in one big file, take a look at Printing multiple ggplots into a single pdf, multiple plots per page.
However, for that many plots it would make a likely make a huge file, which could be problematic to open, especially if you have many points in your plots. In that case it might be better to compare them as separate files.

Autosaving multiple pages of lattice plots

I was wondering if anyone could assist with code below. I have a huge dataset (> 1000 subjects) which I'm trying to visualise individually.
I was fortunate to find a code written by Tony Cookson from R-bloggers which I've modified for my use. The code works ok but the pdfs produced are damaged-essentially they refuse to open. I have a feeling there's bug somewhere but I haven't yet figured out where. Any assistance would be highly appreciated.
library(lattice)
names = LETTERS[1:3]
for(i in 1:3){
mypath <- file.path("myFilepath", "folder containing 'Plots' subfolder ",
"Plots",paste("myplot_", names[i], ".pdf", sep = ""))
pdf(file=mypath)
mytitle = paste("Theoph Plots", names[i])
xyplot(conc ~ Time | Subject, group = Subject, data = Theoph, type = "l",
layout = c(2, 2), main = mytitle)
dev.off()
}
For the code to be reproducible, you need to replace myFilepath, folder containing 'Plots' subfolder and "Plots" with names of actual folders that can be found on your computer. Please see the original on R-bloggers for more details. I would be very happy to clarify anything that seems ambiguous.
Thanks
Edit:
library(lattice)
names = LETTERS[1:3]
for(i in 1:3){
mypath <- file.path("myFilepath", "folder containing 'Plots' subfolder ",
"Plots",paste("myplot_", names[i], ".pdf", sep = ""))
pdf(file=mypath)
mytitle = paste("Theoph Plots", names[i])
print(xyplot(conc ~ Time | Subject, group = Subject, data = Theoph, type = "l",
layout = c(2, 2), main = mytitle))
dev.off()
}
I've managed to find a temporary solution (above) using the print function. However, I'm currently getting all 12 Subjects in the same pdf. What I really want is 4 subjects (2 by 2 matrix) on separate pdfs so making 3 pdfs in total. Anyone know how to do this?
If you're looking to plot a subset of Subjects on each page, then you have to subset your data for each iteration and then plot.
To get 4 Subjects on each page, you can use the following index builder as a basis for subsetting:
(i - 1) * 4 + 1:4
The trick with the Theoph dataset is that the subject "numbers" are actually ordered factors. So you have to convert the above to a factor, or, as a shortcut, to a character vector.
for(i in 1:3){
## Changed mypath to make it reproducible
mypath <- file.path(tempdir(), paste("myplot_", names[i], ".pdf", sep = ""))
pdf(file=mypath)
mytitle = paste("Theoph Plots", names[i])
myIndex <- as.character((i - 1) * 4 + 1:4) # index builder from above
print(xyplot(conc ~ Time | Subject,
data = Theoph[Theoph$Subject %in% myIndex, ],
type = "l", layout = c(2, 2), main = mytitle))
dev.off()
}
The order of the subjects is a bit screwy, since that variable is an ordered factor, as mentioned. To keep the ordering, you could subset on the levels of that factor:
myIndex <- levels(Theoph$Subject)[(i - 1) * 4 + 1:4]
The best way to build your index will depend on your actual data.

For Loop in R for reading and exporting tiff file

I have multiple CSVs as inputs which basically have lat long info and i am exporting the .tiff images which have these lat longs plotted on a map. I want to some how loop this process so as I can read multiple CSVs and hence generate multiple maps(.tiff) corresponding to these CSVs.Any help will be appreciated !!
Here is the code which I am using at present
rm(list=ls())
sclusters_1 <- readLines("C:\\Users\\D85_H.csv")
skip_second <- sclusters_1[-2]
sclusters <- read.csv(textConnection(skip_second), header = TRUE)
library(grDevices)
library(PBSmapping)
library(maptools)
library(sp)
myShapeFile<-importShapefile("C:\\Users\\st99_d00_shp\\st99_d00",readDBF=TRUE, projection = "LL")
ConvUS <- convUL(myShapeFile)
addressEvents<-as.PolyData(sclusters,projection="LL", zone = 15)
uaddressEvents <- convUL(addressEvents)
sclusters_cl <- unique(sclusters$PID)
len <- length(sclusters_cl)
palette(c("dodgerblue3","red3","olivedrab","purple4","turquoise2","orange3","lightskyblue4","mediumorchid3","saddlebrown","skyblue4"))
setwd("C:/Users/")
name, leave .tiff extension
tiff(filename = "Test.tiff",
width = 3750, height = 3142, units = "px", pointsize = 12,
compression = "lzw",
bg = "transparent")
plotMap(ConvUS , xlim=c(-8000,3500), ylim=c(2000,9500), plt=c(0.07,0.97,0.07,0.98), bg = "white", border = "darkgrey", axes=FALSE, xlab=" ",ylab=" ", lty = 1, lwd = 2)
addPoints(uaddressEvents,col=1:len,cex=2.5, pch = "O")
legend("topright",legend = sclusters_cl, cex=0.7, fill=palette())
#close output file stream
dev.off()
Mind you, this is untested:
Since both the import and export filenames are passed as length-1 characters vectors, you can make a matrix like m <- matrix(c("infile1.csv", "outfile1.tiff", "infile2.csv", "outfile2.tiff"),nrow=2).
Then you can just wrap the entire thing in a for loop over the columns of that matrix, e.g. for(j in 1:ncol(m)). Then just replace "C:\\Users\\st99_d00_shp\\st99_d00" with m[1,j] and "Test.tiff" with m[2,j].
Even better practice might be to wrap the entire thing in a function and then write a separate loop that just calls the function. For example:
myTIFF <- function (infile, outfile) {
# stuff you want to do to each pair of input and output files
}
m <- matrix(c(
"infile1.csv", "outfile1.tiff",
"infile2.csv", "outfile2.tiff"
# and so on
), nrow = 2)
for(j in 1:ncol(m)) myTIFF(m[1, j], m[2, j])
Note also that R has function called dir that automatically extracts the contents of a directory as a character vector, in the way that ls does for variables in the current environment. If you have a large number of CSV files, you can use this (possibly in conjunction with grep) to generate the matrix m programmatically rather than typing it by hand.

Resources