I would like to plot multiple .TIFF images in R and add individual titles to them. Without the titles, this piece of code gets the job done:
require(raster)
setwd("...")
files = list.files(pattern="*.tif")
tiff("balanded_1.tiff", units="in", width=21, height=26, res=300, compression = 'lzw') #for saving
par(mfrow=c(5,3))
for (i in 1:15) {
plotRGB(brick(files[i]))
}
dev.off() #save figure
However, if I try to add individual titles to the images using 'plotRGB()', it automatically adds axes to them (because 'axes=TRUE' becomes a requirement in the 'plotRGB()' function), and I get something like this:
plotRGB(brick(files[2]), axes=TRUE, main="TITLE", xlab="", ylab="")
I understand that 'plotRGB()' is probably not the right function for the job (since I am not plotting maps), but I wonder if there is a way to make it work? If not, is there an alternative I could use? Thank you in advance.
I managed to find a solution to this problem using a more appropriate package for image manipulation:
require(magick)
setwd("...")
files = list.files(pattern="*.tif")
tiff("balanded_1.tiff", units="in", width=21, height=26, res=300, compression = 'lzw')
par(mfrow=c(5,3))
for (i in 1:15) {
name <- files[i]
lag <- strsplit(name, "_")[[1]][2] #get the name right for the image
match <- strsplit(name, "_")[[1]][4]
lead <- strsplit(name, "_")[[1]][6]
lead <- strsplit(lead, ".tiff")[[1]][1]
name <- paste(" Lag=",lag,", Match=1:",match,", Lead=",lead, sep = "") #put the name together
img <- image_annotate(image_read(files[i]), name, font = 'Times', size = 120) #read the image and add the name
img <- image_crop(img, "1500x1050")
plot(img)
}
dev.off() #save figure
Related
I have multiple csv files, each with a single column.
I want to read them and plot their density distribution in a single plot.
can anyone help me?
There are answers elsewhere about
reading multiple csv files so I will mainly concentrate on the density plotting part. Since you did not provide any data, I will use the built-in iris data to create some example files. This first step is to make a reusable example. I am assuming that you already have the data on the disk and have a list of the file names.
## Create some test data
FileNames = paste(names(iris[,1:4]), ".csv", sep="")
for(i in 1:4) {
write.csv(iris[,i], FileNames[i], row.names=FALSE)
}
So, on to the density plots. There is one small sticky point. Each of the different density plots will cover a different range of x and y values. If you want them all in one plot, you will need to leave enough room in your plot to hold them all. The code below first computes that range, then makes the plots.
## Read in all of the data from csv
DataList = list()
for(i in seq_along(FileNames)) {
DataList[[i]] = read.csv(FileNames[i], header=T)[[1]]
}
## Find the range that we will need to include all plots
XRange = range(DataList[[1]])
YRange = c(0,0)
for(i in seq_along(DataList)) {
Rx = range(DataList[[i]])
XRange[1] = min(XRange[1], Rx[1])
XRange[2] = max(XRange[2], Rx[2])
YRange[2] = max(density(DataList[[i]], na.rm=T)$y, YRange[2])
}
## Now make all of the plots
plot(density(DataList[[1]], na.rm=T), xlim=XRange, ylim=YRange,
xlab=NA, ylab=NA, main="Density Plots")
for(i in seq_along(DataList)) {
lines(density(DataList[[i]], na.rm=T), col=i)
}
legend("topright", legend=FileNames, lty=1, col=1:4, bty='n')
When I try to save this particular plot as an image, I only get an empty white image file. With this same code I managed to save multiple other "normal" plots, but it just won't work for find_droughts function (maybe also for some others).
I can save the plot manually by clicking "Export" in the Viewer, but I have a lot of plots to save and I would really like to do it using code.
This code generates the plot I have in mind:
library(lfstat)
# random data
date<-seq(from=as.Date("2018-01-01"), to=as.Date("2018-12-31"), by="days")
flow<-c(runif(150, min=50, max=180),runif(95, min=25, max=50),runif(120, min=50, max=400))
# dataframe
flow.df<-data.frame(day(date),month(date),year(date),flow)
names(flow.df)<-c("day", "month", "year", "flow")
#dataframe to lfobj
lfobj <- createlfobj(flow.df,hyearstart = 1, baseflow = FALSE)
# lfobj to xts
flowunit(lfobj)<-"m^3/s"
xts<-as.xts(lfobj)
# find droughts
droughts<-find_droughts(xts, threshold=47, drop_minor = 0)
# Save plot as .png
savehere<-"C:/.../"
filename<-"myplot.png"
mypath <- file.path(paste(savehere,filename, sep = ""))
png(file=mypath)
plot(droughts)
dev.off()
I need help with the last step - "# Save plot as .png".
And if anybody knows a way to change title of this plot, names of axis labels and so on, this would also help.
I think the reason is that the default plot from the 'find_droughts' function is an interactive plot based on dygraph package.
I can think of two ways to overcome your issue.
If you want to plot static png, you can define on the plot function the type of the plot, so it's not the default (interactive) anymore. Based on your code, it will be:
# Save plot as .png
savehere <- "C:/.../"
filename <- "myplot.png"
mypath <- file.path(paste(savehere,filename, sep = ""))
png(file=mypath)
plot(droughts, type='l') # by defining type 'l', it will provide a plot of xts object, which is static
dev.off()
If you want to plot an interactive plot, you can do something as below:
# Save plot as .html
library(htmlwidgets) # for saving html files
savehere <- "C:/.../"
filename <- "myplot.html"
mypath <- file.path(paste(savehere,filename, sep = ""))
InteractivePlot <- plot(droughts)
saveWidget(InteractivePlot , file=mypath)
# the above function will generate the interactive plot as an html file, but also a folder, which you might want to delete, since it's not required for viewing the plot. For deleting this folder you can do the following
foldername <- "myplot_files"
mypath <- file.path(paste(savehere,foldername , sep = ""))
unlink(mypath, recursive = T)
Hope this helps.
Hi I am new to R and am trying to plot multiple files as lines in a scatter plot. I was able to get the plot but not when I try to add legend to the plot. I want the legend with name of the file in the same color as the color of the line made from that file. I tried using the following suggestion from a previous thread -
xlist<-list.files(pattern = NULL)
first=TRUE
cl <- rainbow(22)
for(i in xlist) {
table <- read.table((i),header=T,sep="\t")
table <- table[, 1:2]
if (first) {
plot(table,xlab='Distance from center',ylab='Coverage',ylim=c(0,70),col=1, type="n")
lines(table) #plot and add lines
legend("top", y=NULL, legend = i, col=1)
par(new=T)
first=FALSE
}
else {
lines(table,col=cl[i]) #To add another file to the plot as another line
par(new=F)
plotcol[i] <- cl[i]
legend("top", y=NULL, legend = i, col=plotcol)
}
}
The error is get is - Error in plotcol[i] <- cl[i] : object 'plotcol' not found. Please let me know what I am missing or if there is a better way to plot the lines with different colors and get legend with names of the files with the same color as the lines. Thank you.
I had to make some reproducible examples to get it to work, but the following script works to make the lengends and line colors the same:
#random data
test.df1=data.frame(runif(100)*0.2,runif(100)*0.2)
test.df2=data.frame(runif(100)*0.5,runif(100)*0.5)
test.df3=data.frame(runif(100),runif(100))
test.df4=data.frame(runif(100)*2,runif(100)*2)
test.list=list(test.df1=test.df1,test.df2=test.df2,test.df3=test.df3,test.df4=test.df4) # I used this instead of reading in files from read.table, you shouldn't need this
xlist=c('test.df1','test.df2','test.df3','test.df4') #the list of files
first=TRUE
cl <- rainbow(length(xlist)) #colors dedicated to your list
names(cl)=xlist #this names the vector elements so you can reference them
for(i in xlist) {
i.table <- test.list[[i]]
i.table <- i.table[,c(1:2)]
if (first) {
plot(i.table,xlab='Distance from center',ylab='Coverage',xlim=c(0,2),ylim=c(0,2),col=cl[i], type="n")
lines(i.table,col=cl[i]) #plot and add lines
par(new=T)
first=FALSE
}
else {
lines(i.table,col=cl[i]) #To add another file to the plot as another line
par(new=F)
plotcol <- c(plotcol,cl[i])# pulls colors from the cl vector
}
}
legend("top", y=NULL, legend =xlist, text.col=cl) #label colors should now match
Try ggplot2 package in R. You wouldn't have to code as much too!
https://www.rstudio.com/wp-content/uploads/2015/12/ggplot2-cheatsheet-2.0.pdf
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")
I would like to plot a simple graphic. I have a dat set with n rowns and k columns, in which each row has a a sequence of 0 and 1. I would like to plot exactly this sequence for all rows.
Actually I want to reproduce the figure 24.1, p. 516, of Gelman and Hill's book (Data aAnalysis Using Regression and Multilevel/Hierarchical Models). I suspect that he made the graphic in Latex, but it seems quite ridiculous that I'm not able to repplicate this simple graphic in R. The figue is something like this. As you can see from the link, the "ones" are replaced by "S" and "zeros" by ".". It's a simple graphic, but it shows each individual response by time.
I would go with a formatted text output using sprintf. Much cleaner and simpler. If you still want a plot, you could go with the following:
Given matrix tbl containing your data:
tbl <- matrix(data=rep(0:1,25), nrow=5)
You can generate a plot as:
plot(1, 1, xlim=c(1,dim(tbl)[2]+.5), ylim=c(0.5,dim(tbl)[1]), type="n")
lapply(1:dim(tbl)[1], function(x) {
text(x=c(1:dim(tbl)[2]), y=rep(x,dim(tbl)[2]), labels=tbl[x,])
})
Using this as a base you can play around with the text and plot args to stylize the plot the way you wish.
Here are two possible solutions, based on fake data generated with this helper function:
generate.data <- function(rate=.3, dim=c(25,25)) {
tmp <- rep(".", prod(dim))
tmp[sample(1:prod(dim), ceiling(prod(dim)*rate))] <- "S"
m <- matrix(tmp, nr=dim[1], nc=dim[2])
return(m)
}
Text-based output
x <- generate.data()
rownames(x) <- colnames(x) <- 1:25
capture.output(as.table(x), file="res.txt")
The file res.txt include a pretty-printed version of the console output; you can convert it to pdf using any txt to pdf converter (I use the one from PDFlib). Here is a screenshot of the text file:
Image-based output
First, here is the plotting function I used:
make.table <- function(x, labels=NULL) {
# x = matrix
# labels = list of labels for x and y
coord.xy <- expand.grid(x=1:nrow(x), y=1:ncol(x))
opar <- par(mar=rep(1,4), las=1)
plot.new()
plot.window(xlim=c(0, ncol(x)), ylim=c(0, nrow(x)))
text(coord.xy$x, coord.xy$y, c(x), adj=c(0,1))
if (!is.null(labels)) {
mtext(labels[[1]], side=3, line=-1, at=seq(1, ncol(x)), cex=.8)
mtext(labels[[2]], side=2, line=-1, at=seq(1, nrow(x)), cex=.8, padj=1)
}
par(opar)
}
Then I call it as
make.table(x, list(1:25, 1:25))
and here is the result (save it as png, pdf, jpg, or whatever).
As far as I can see, this is a text table. I am wondering why you want to make it a graph? Anyway, quick solutions are (either way)
make the text table (by programming or typing) and make its screenshot and embed the image into the plot.
make a blank plot and put the text on the plot by programming R with "text" function. For more info on "text", refer to http://cran.r-project.org/doc/contrib/Lemon-kickstart/kr_adtxt.html