R: Automatically create ggplots visualization from multiple rasters - r

building my path in R, So I am still very bad especially in running loops and complexes functions...
What I am interested about is to automatically read a series of rasters in a particular folder and generate a simple ggplot visualization out of it (for each one of the rasters). Possibly exporting it to some folder would be also nice.
The further idea would be to overlap these visualizations and create an animated GIF, but this I can perhaps do outside of R... Just creating the maps would already be really nice...
With this I can load all rasters in my R enviroment:
myfiles = list.files(pattern = "*.asc")
for (i in 1:length(myfiles)) assign(myfiles[i], raster::raster(myfiles[i]))
While the basic ggplot code to build one of the map would be:
#Loading an example raster
hflow = raster::raster("D:/R.avaflow_graphs/Erla_E1_F01_results/Erla_E1_F01_ascii/Erla_E1_F01_hflow0000.asc")
hflow_spdf <- as(hflow, "SpatialPixelsDataFrame") # Creating a spdf
hflow_df <- as.data.frame(hflow_spdf) # Creating a df
colnames(hflow_df) <- c("value", "x", "y") # Assign x,y,values
ggplot() + # plotting the map
geom_tile(data=hflow_df, aes(x=x, y=y, fill=value), alpha=0.8) +
coord_equal()
For inspiration, I've been checking these 3 links, but still couldn't make it happen...
R apply raster function to a list of characters
https://gis.stackexchange.com/questions/377444/plotting-a-raster-stack-with-ggplot2
https://www.r-bloggers.com/2020/07/writing-functions-to-automate-repetitive-plotting-tasks-in-ggplot2/
Thanks beforehand!
PL

The first part can be easily done with a simple sapply to create a plot for each image and save it to disk using ggsave. The gif creation can also be done inside R using the magick package. You just need to read the exported plots as images, then perform a join, animate and export as gif. Here's the code to perform the complete procedure.
library(magick)
library(ggplot2)
# List all raster files
myfiles = list.files(pattern = "*.asc")
# Loop to create plots for each image
sapply(myfiles, function(x){
# Get image names
im_name <- gsub("\\.[A-z]+$", "", x)
# Load image as raster
im <- raster::raster(x)
# Transform to df
hflow_spdf <- as(im, "SpatialPixelsDataFrame") # Creating a spdf
hflow_df <- as.data.frame(hflow_spdf) # Creating a df
colnames(hflow_df) <- c("value", "x", "y") # Assign x,y,values
# Make plot
ggplot() + # plotting the map
geom_tile(data=hflow_df, aes(x=x, y=y, fill=value), alpha=0.8) +
# Added fill_distiller to define filling palette
scale_fill_distiller(type = "seq",
palette = "Greys") +
coord_equal()
# Save plot
ggsave(paste0(im_name, ".png"),
device = "png",
width = 10,
height = 10,
units = "cm",
dpi = 150)
})
# Create gif
# List plots files
plots <- list.files(pattern = ".png")
# Read the plots as image
plots_list <- lapply(plots, image_read)
# Join the list of plots
plot_joined <- image_join(plots_list)
# Create animation, defining the frames per second (fps)
plot_animated <- image_animate(plot_joined, fps = 1)
# Write animation as gif
image_write(image = plot_animated,
path = "plots_anim.gif")

Related

R : Create list of plots with for loop

I try to create a list of plots of my data using a for loop to filter (="TAB_tmp2") and add the new plot in the list (="ListeGRAPH"). I think the problem comes from the difference of filter data table (="TAB_tmp2").
I have read several topics on the web about that but I can't find a solution which could works in this case.
My code :
rm(list=ls()) # delete objects
#====================================
# Create data for the example
#====================================
TAB = data.frame(Types_Mesures = c(rep(1,3),rep(2,5),rep(3,10)))
TAB$ID_mesuresParType=NA
TAB$Mesures=log(c(1:length(TAB$Types_Mesures)))
Nb_Types=length(unique(TAB$Types_Mesures)) # in the real data, the number of "Types_Mesures" can change
for (x in 1:Nb_Types) {
TAB_tmp=TAB[TAB$Types_Mesures==x,2]
TAB[TAB$Types_Mesures==x,2]=c(1:length(TAB_tmp))
}
#====================================
# List of plots
#====================================
library(gridExtra)
library(ggplot2)
INPUTDirectory= "D:/TEST/"
setwd(dir=INPUTDirectory)
ListeGRAPH <- list()
for (x in 1:Nb_Types) {
TAB_tmp2=TAB[TAB$Types_Mesures==x,]
ListeGRAPH[[x]] <- ggplot(data = TAB_tmp2) +
geom_line(aes(x = TAB_tmp2$ID_mesuresParType, y = TAB_tmp2$Mesures))
# #Save graph
# png(filename = paste("TAB_plot_T",x,".png", sep = ""))
# print(ListeGRAPH[[x]])
# graphics.off()
}
gridExtra::grid.arrange(grobs = ListeGRAPH)
When I run the code, I have this error :
Error: Aesthetics must be either length 1 or the same as the data (3):
x, y
It seems that grid.arrange don't accept plots of different dimensions ?
How could I do to make the list of plots with this kind of table ? In my real data the number of "Types_Mesures" can change.
More over, I think the for loop don't allow to use a temporary variable (="TAB_tmp2") to create the list of plot but this code works when I save my plot in PNG files.
Thanks a lot for you help !
The problem is actually not with grid.arrange. When you're creating the plots with ggplot, you do not need to use $ for indexing of columns. So instead of:
ListeGRAPH[[x]] <- ggplot(data = TAB_tmp2) +
geom_line(aes(x = TAB_tmp2$ID_mesuresParType, y = TAB_tmp2$Mesures))
you should use:
ListeGRAPH[[x]] <- ggplot(data = TAB_tmp2) +
geom_line(aes(x = ID_mesuresParType, y = Mesures))
and then you will be able to plot the results using grid.arrange.

Save and Load a ggplot plot

I am working on a large shinydashboard and was keeping my code for modeling in a separate file from the main app.R. The problem is that I need to plot my data. This requires that I save my ggplots from one file and load them in my main app.R file. How can I save my ggplots and load them.
As a simple example lets say I have the following
#make plot
> p <- mtcars %>%
ggplot(aes(x = mpg, y = cyl))+geom_point()
#save plot
> save(file=here::here("plots/a_plot.Rdata"),p)
#load plot
> p <- load(file=here::here("plots/trans_arima.Rdata"))
> p
[1] "p"
How can I load my ggplot?
You can save your plot as a png file and then load it back into youyr file
you have several option for saving your plot. you could use ggplot2s' ggsave()
function or you could use the save_plot() from the cowplot package. save_plot() is said to
give you more flexibility when it comes file adjusting hence my pick.
You can explore both.
refer to https://rdrr.io/cran/cowplot/man/save_plot.html to read more about save_plot.
tmp = data.frame(first = c('a','b','c','d','e','f','g','h','i','j','k','l','m','n'),
second = c(2,3,4,5,2,3,4,5,6,3,4,4,6, 7))
plot_tmp = ggplot(tmp, aes(first, second)) + geom_bar(stat = 'identity')
dev.new()
if("png" %in% installed.packages()){
library(png)
}else{
install.packages("png")
library(png)
}
save_plot("~/plot_tmp.png", plot_tmp, base_height = NULL, base_aspect_ratio = 1.618,
base_width = 6)
Use the following steps to load files into your shiny using by using the
#read plot
library(OpenImageR)
img<-OpenImageR::readImage("~/plot_tmp.png")
imageShow(img)
Hopefully this helps. To read more about OpenImageR and how you can use it in shiny please go to https://cran.r-project.org/web/packages/OpenImageR/vignettes/The_OpenImageR_package.html
have fun!!!

combine multiple plots to a gif

Im trying to use the caTools package to combine multiple plots into a gif.
My basic code looks like :
for( i in 1:100){
plot(....) // plots few points and lines, changes slightly with each i
}
I would like to combine these to a gif to see the "evolution" of the plot.
However for write.gif() from caTools, I need to give an image as an input.
For each i, how do I convert the plot into an image without
saving to disc as an intermediate step
depending on ImageMagick or similar external dependencies.
Please feel free to point out if this is a duplicate. [ Creating a Movie from a Series of Plots in R doesnt seem to answer this ]
EDIT: Basically this requires us to convert a plot to a matrix. Since this very likely happens every time someone saves a plot, it should not be very difficult. However Im not able to get hold of how to exactly do this.
I suggest using the animation package and ImageMagick instead:
library(animation)
## make sure ImageMagick has been installed in your system
saveGIF({
for (i in 1:10) plot(runif(10), ylim = 0:1)
})
Otherwise you could try it in the veins of this (plenty of room for optimization):
library(png)
library(caTools)
library(abind)
# create gif frames and write them to pngs in a temp dir
dir.create(dir <- tempfile(""))
for (i in 1:8) {
png(file.path(dir, paste0(sprintf("%04d", i), ".png")))
plot(runif(10), ylim = 0:1, col = i)
dev.off()
}
# read pngs, create global palette, convert rasters to integer arrays and write animated gif
imgs <- lapply(list.files(dir, full.names = T), function(fn) as.raster(readPNG(fn)))
frames <- abind(imgs, along = 3) # combine raster pngs in list to an array
cols <- unique(as.vector(frames)) # determine unique colors, should be less then 257
frames <- aperm(array(match(frames, cols) - 1, dim = dim(frames)), c(2,1,3)) # replace rgb color codes (#ffffff) by integer indices in cols, beginning with 0 (note: array has to be transposed again, otherwise images are flipped)
write.gif(
image = frames, # array of integers
filename = tf <- tempfile(fileext = ".gif"), # create temporary filename
delay = 100, # 100/100=1 second delay between frames
col = c(cols, rep("#FFFFFF", 256-length(cols))) # color palette with 256 colors (fill unused color indices with white)
)
# open gif (windows)
shell.exec(tf)
Is that what you are looking for?
library(ggplot2)
a <- 0:10
df <- data.frame(a=a,b=a)
steps <-function(end){
a <- ggplot(df[1:end,], aes(a,b)) +
geom_point() +
scale_x_continuous(limits=c(0,10)) +
scale_y_continuous(limits=c(0,10))
print(a)
}
gif <- function() {
lapply(seq(1,11,1), function(i) {
steps(i)
})
}
library(animation)
saveGIF(gif(), interval = .2, movie.name="test.gif")
I liked #ttlngr's answer but I wanted something a bit simpler (it still uses ImageMagick).
saveGIF({
for (i in 1:10){
a <- ggplot(df[1:i,], aes(a,b)) +
geom_point() +
scale_x_continuous(limits=c(0,10)) +
scale_y_continuous(limits=c(0,10))
print(a)}
}, interval = .2, movie.name="test.gif")

Save multiple ggplot2 plots as R object in list and re-displaying in grid

I would like to save multiple plots (with ggplot2) to a list during a large for-loop. And then subsequently display the images in a grid (with grid.arrange)
I have tried two solutions to this:
1 storing it in a list, like so:
pltlist[["qplot"]] <- qplot
however for some reason this does save the plot correctly.
So I resorted to a second strategy which is recordPlot()
This was able to save the plot correctly, but unable to
use it in a grid.
Reproducable Example:
require(ggplot2);require(grid);require(gridExtra)
df <- data.frame(x = rnorm(100),y = rnorm(100))
histoplot <- ggplot(df, aes(x=x)) + geom_histogram(aes(y=..density..),binwidth=.1,colour="black", fill="white")
qplot <- qplot(sample = df$y, stat="qq")
pltlist <- list()
pltlist[["qplot"]] <- qplot
pltlist[["histoplot"]] <- histoplot
grid.arrange(pltlist[["qplot"]],pltlist[["histoplot"]], ncol=2)
above code works but produces the wrong graph
in my actual code
Then I tried recordPlot()
print(histoplot)
c1 <- recordPlot()
print(qplot)
c2 <- recordPlot()
I am able to display all the plots individually
but grid.arrange produces an error:
grid.arrange(replayPlot(c1),replayPlot(c2), ncol=2) # = Error
Error in gList(list(wrapvp = list(x = 0.5, y = 0.5, width = 1, height = 1, :
only 'grobs' allowed in "gList"
In this thread Saving grid.arrange() plot to file
They dicuss a solution which utilizes arrangeGrob() instead
arrangeGrob(c1, c1, ncol=2) # Error
Error in vapply(x$grobs, as.character, character(1)) :
values must be length 1,
but FUN(X[[1]]) result is length 3
I am forced to use the recordPlot() instead of saving to a list since this does not produce the same graph when saved as when it is plotted immediately, which I unfortunately cannot replicate, sorry.
In my actual code I am doing a large for-loop, looping through several variables, making a correlation with each and making scatterplots, where I name the scatterplots dependent on their significans level. I then want to re-display the plots that were significant in a grid, in a dynamic knitr report.
I am aware that I could just re-plot the plots that were significant after the for-loop instead of saving them, (I can't save as png while doing knitr either). However I would like to find a way to dynammically save the plots as R-objects and then replot them in a grid afterwards.
Thanks for Reading
"R version 3.2.1"
Windows 7 64bit - RStudio - Version 0.99.652
attached base packages:
[1] grid grDevices datasets utils graphics stats methods base
other attached packages:
[1] gridExtra_2.0.0 ggplot2_1.0.1
I can think of two solutions.
1. If your goal is to just save the list of plots as R objects, I recommend:
saveRDS(object = pltlist, file = "file_path")
This way when you wish to reload in these graphs, you can just use readRDS(). You can then put them in cowplot or gridarrange. This command works for all lists and R Objects.
One caveat to this approach is if settings/labeling for ggplot2 is dependent upon things in the environment (not the data, but stuff like settings for point size, shape, or coloring) instead of the ggplot2 function used to make the graph), your graphs won't work until you restore your dependencies. One reason to save some dependencies is to modularize your scripts to make the graphs.
Another caveat is performance: From my experience, I found it is actually faster to read in the data and remake individual graphs than load in an RDS file of all the graphs when you have a large number of graphs (100+ graphs).
2. If your goal is to save an 'image' or 'picture' of each graph (single and/or multiplot as .png, .jpeg, etc.), and later adjust things in a grid manually outside of R such as powerpoint or photoshop, I recommend:
filenames <- c("Filename_1", "Filename_2") #actual file names you want...
lapply(seq_along(pltlist), function(i) {
ggsave(filename = filenames[i], plot = pltlist[[i]], ...) #use your settings here
})
Settings I like for single plots:
lapply(seq_along(pltlist), function(i) ggsave(
plot = pltlist[[i]],
filename = paste0("plot_", i, "_", ".tiff"), #you can even paste in pltlist[[i]]$labels$title
device = "tiff", width=180, height=180, units="mm", dpi=300, compression = "lzw", #compression for tiff
path = paste0("../Blabla") #must be an existing directory.
))
You may want to do the manual approach if you're really OCD about the grid arrangement and you don't have too many of them to make for publications. Otherwise, when you do grid.arrange you'll want to do all the specifications there (adjusting font, increasing axis label size, custom colors, etc.), then adjust the width and height accordingly.
Reviving this post to add multiplot here, as it fits exactly.
require(ggplot2)
mydd <- setNames( data.frame( matrix( rep(c("x","y","z"), each=10) ),
c(rnorm(10), rnorm(10), rnorm(10)) ), c("points", "data") )
# points data
# 1 x 0.733013658
# 2 x 0.218838717
# 3 x -0.008303382
# 4 x 2.225820069
# ...
p1 <- ggplot( mydd[mydd$point == "x",] ) + geom_line( aes( 1:10, data, col=points ) )
p2 <- ggplot( mydd[mydd$point == "y",] ) + geom_line( aes( 1:10, data, col=points ) )
p3 <- ggplot( mydd[mydd$point == "z",] ) + geom_line( aes( 1:10, data, col=points ) )
multiplot(p1,p2,p3, cols=1)
multiplot:
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
library(grid)
# Make a list from the ... arguments and plotlist
plots <- c(list(...), plotlist)
numPlots = length(plots)
# If layout is NULL, then use 'cols' to determine layout
if (is.null(layout)) {
# Make the panel
# ncol: Number of columns of plots
# nrow: Number of rows needed, calculated from # of cols
layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
ncol = cols, nrow = ceiling(numPlots/cols))
}
if (numPlots==1) {
print(plots[[1]])
} else {
# Set up the page
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
# Make each plot, in the correct location
for (i in 1:numPlots) {
# Get the i,j matrix positions of the regions that contain this subplot
matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
layout.pos.col = matchidx$col))
}
}
}
Result:

NP chart using ggplot2

how i can generate NP chart using ggplot2?
I made simple Rscript which generates bar, point charts. I am supplying data by csv file. how many columns do i need to specify and in gplot functions what arguments do i need to pass?
I am very new to R, ggplots.
EDIT :
This is what is meant by an NP chart.
Current code attempt:
#load library ggplot2
library(ggplot2)
#get arguments
args <- commandArgs(TRUE)
pdfname <- args[1]
graphtype <- args[2]
datafile <- args[3]
#read csv file
tasks <- read.csv(datafile , header = T)
#name the pdf from passed arg 1
pdf(pdfname)
#main magic that generates the graph
qplot(x,y, data=tasks, geom = graphtype)
#clean up
dev.off()
In .csv file there are 2 columns x,y i call this script by Rscript cne.R 11_16.pdf "point" "data.csv".
Thanks you very much #mathematical.coffee this is what i need but
1> I am reading data from csv file which contains following data
this is my data
Month,Rate
"Jan","37.50"
"Feb","32.94"
"Mar","25.00"
"Apr","33.33"
"May","33.08"
"Jun","29.09"
"Jul","12.00"
"Aug","10.00"
"Sep","6.00"
"Oct","23.00"
"Nov","9.00"
"Dec","14.00"
2> I want to display value on each plotting point. and also display value for UCL,Cl,LCL, and give different label to x and y.
Problem when i read data it is not in the same order as in csv file. how to fix it?
You combine ggplot(tasks,aes(x=x,y=y)) with geom_line and geom_point to get the lines connected by points.
If you additionally want the UCL/LCL/etc drawn you add in a geom_hline (horizontal line).
To add text to these lines you can use geom_text.
An example:
library(ggplot2)
# generate some data to use, say monthly up to a year from today.
n <- 12
tasks <- data.frame(
x = seq(Sys.Date(),by="month",length=n),
y = runif(n) )
CL = median(tasks$y) # substitue however you calculate CL here
LCL = quantile(tasks$y,.25) # substitue however you calculate LCL here
UCL = quantile(tasks$y,.75) # substitue however you calculate UCL here
limits = c(UCL,CL,LCL)
lbls = c('UCL','CL','LCL')
p <- ggplot(tasks,aes(x=x,y=y)) + # store x/y values
geom_line() + # add line
geom_point(aes(colour=(y>LCL&y<UCL))) + # add points, colour if outside limits
opts(legend.position='none', # remove legend for colours
axis.text.x=theme_text(angle=90)) # rotate x axis labels
# Now add in the limits.
# horizontal lines + dashed for upper/lower and solid for the CL
p <- p + geom_hline(aes(yintercept=limits,linetype=lbls)) + # draw lines
geom_text(aes(y=limits,x=tasks$x[n],label=lbls,vjust=-0.2,cex=.8)) # draw text
# display
print(p)
which gives:

Resources