plot multiple figures interactively with split.screen and hold one constant - r

I am using R to plot a multifgure image with interactive capability in one of them. I'm using split.screen to do this (as I tried unsuccesfuly to do it right with par() and base R graphics.
My goal is to hold the display of each screen(1) jth plot, while the screen(2) plot figure updates interactively k times..
But even though I set erase = FALSE or TRUE, each time it iterates through the subloop, the first plot is cleared and displays a blank image. Any ideas on how to hold the first plot image, each time the sub loop, k updates its graphics?
split.screen(figs=c(1,2),erase=TRUE)
for(j in 1:5){
screen(1)
plot(rnorm(3))
screen(2)
for(k in 1:5){
plot(rnorm(3))
par(ask=TRUE)
}
}
update from help.
These functions are totally incompatible with the other mechanisms for arranging plots on a device: par(mfrow), par(mfcol)'and'layout().
I guess that explains the par(ask=TRUE). I'm still interested if anyone can do this using par() and base graphics functions.
I couldn't find any par() variables that would explicitly specify one of the two screens to plot on at any step, while allowing par(ask=T) to update in a subloop, which is what split.screen() was able to do.

Give Hmisc::subplot a try:
## draw first plot
par(mfcol=c(1,2), xpd=NA)
plot(rnorm(3))
plot(1,1) # dummy plot
## update subplot k times
for(k in 1:5) {
rect(grconvertX(par("fin")[1], from="inches"),
grconvertY(0, from="inches"),
grconvertX(par("fin")[1]*2, from="inches"),
grconvertY(par("fin")[2], from="inches"), col="white", border=NA) ## cover-up
subplot( plot(rnorm(3)), 1, 1, size=par("pin") )
readline("Hit <Return> to see next plot: ")
}

Adding a flush.console() and Sys.sleep() should do it.
split.screen(figs=c(1,2),erase=TRUE)
for(j in 1:5){
screen(1)
plot(rnorm(3))
flush.console()
Sys.sleep(0.5)
for(k in 1:5){
screen(2)
plot(rnorm(3))
par(ask=TRUE)
flush.console()
Sys.sleep(0.5)
}
}
That will still suppress the par(ask=TRUE) as per the warnings, but it should prevent the first plot going blank whilst the second iterates.

Related

How to save several plots from an own function into a list in R?

I have created one function that contains two types of plots and it will give you one image. However, the title of this image will change depending on one list, so, you will have several plots but different title.
(The original function will change the numbers that the plot uses but, in essence, is what I need).
This is the example that I have created.
list_genes <- c("GEN1", "GEN2", "GEN3")
myfunction <- function(x,y){
for(gene in list_genes){
# This to draw both plots
par(mfrow=c(2,1))
plot(x,y, main=paste0("Plot of ", gene))
hist(x, main=paste0("Plot of ", gene))
}
}
myfunction(x=c(1,5,6,2,4),y=c(6,10,53,1,5))
Since the list has 3 elements, we get 3 plots.
However, as I need to create a presentation with all the plots that I generate, I found this post with a solution to create slides for several plots inside a for loop. It is what I want, but for that, I need to save my plots into a list/variable.
object <- myfunction(x=c(1,5,6,2,4),y=c(6,10,53,1,5))
> object
NULL
I found this post (which gives you an interesting solution) but, the plots still cannot be saved into an object.
calling_myfunc <- function(){
myfunction(x=c(1,5,6,2,4),y=c(6,10,53,1,5))
}
calling_myfunc()
object <- calling_myfunc()
> object
NULL
My final objective is to create a presentation (automatically) with all of the plots that I generate from my function. As I saw in this post. But I need to save the plots into a variable.
Could anyone help me with this?
Thanks very much in advance
Although I couldn't find the way to save the plots into an object, I found a way to create a presentation with those images thanks to this post and the export package.
library(export)
list_genes <- c("GEN1", "GEN2", "GEN3")
myfunction <- function(x,y){
for(gene in list_genes){
# This to draw both plots
par(mfrow=c(2,1))
plot(x,y, main=paste0("Plot of ", gene))
hist(x, main=paste0("Plot of ", gene))
graph2ppt(file="plots.pptx", width=6, height=5,append=TRUE) } }
myfunction(x=c(1,5,6,2,4),y=c(6,10,53,1,5))
Of course, the width and height of the plots can be changed or put them as a parameter in the function.
Since the package is not available in CRAN for my current R version (4.1.2), I downloaded it from GitHub:
devtools::install_github("tomwenseleers/export")
In addition, I have found another package that I can use for the same purpose (although it adds one extra slide at the beginning, I don't know why)
library(eoffice)
list_genes <- c("GEN1", "GEN2", "GEN3")
myfunction <- function(x,y){
for(gene in list_genes){
# This to draw both plots
par(mfrow=c(2,1))
plot(x,y, main=paste0("Plot of ", gene))
hist(x, main=paste0("Plot of ", gene))
topptx(file="plots.pptx", width=6, height=5,append=TRUE)
}
}
myfunction(x=c(1,5,6,2,4),y=c(6,10,53,1,5))
PS: I found the solution to create a presentation --> How to create a presentation in R with several plots obtained by a function?

Multiple plotting device in R

To save multiple plots in a pdf, I do this:
pdf("plot1.pdf")
for(i in 1:10){
p <- plot(rnorm(10))
p
}
dev.off()
Is there any way I can open two pdf and print different plots in them. Something like
pdf("plot1.pdf")
pdf("plot2.pdf")
for(i in 1:10){
p1 <- plot(rnorm(10))
p1 # print this in plot1.pdf
p2 <- plot(rnorm(100))
p2 # print this in plot2.pdf
}
dev.off()
You can only have one graphics device active at a time, but you can switch between them. R tracks a list of open devices (dev.list()) in the order in which you create them. For example you can do
pdf("plot1.pdf")
pdf("plot2.pdf")
for(i in 1:3){
dev.set(dev.prev()) #go back to plot1.pdf
plot(rnorm(10))
dev.set(dev.next()) # jump ahead to plot2.pdf
plot(rnorm(100))
}
dev.off()
dev.off()
(Note it doesn't make sense to store the result of plot(rnorm(10)) to a variable because it doesn't return anything. Base plotting typically just have the side effect of drawing to the screen.)

Multiple graphs within plot with loop

How to get graph for each column of data.frame within one plot with loop? Must be easy just can't figure it out.
Sample data:
rdata <- data.frame(y=rnorm(1000,2,2),v1=rnorm(1000,1,1),v2=rnorm(1000,3,3),
v3=rnorm(1000,4,4),v4=rnorm(1000,5,5))
What I have tried?
library(lattice)
p <- par(mfrow=c(2,2))
for(i in 2:5){
w <- xyplot(y~rdata[,i],rdata)
print(w)
}
par(p)
If you don't have to use lattice you can just use base plot instead and it should work as you want.
p <- par(mfrow=c(2,2))
for(i in 2:5){
plot(y~rdata[,i],rdata)
}
par(p)
If you want to use lattice look this answer. Lattice ignores par, so you have to do some more work to achieve what you want.
Inorder to easily arrange a bunch of lattice plots, I like to use the helper function print.plotlist. It has a layout= parameter that acts like the layout() function for base graphics. For example, you could call
rdata <- data.frame(y=rnorm(1000,2,2),v1=rnorm(1000,1,1),v2=rnorm(1000,3,3),
v3=rnorm(1000,4,4),v4=rnorm(1000,5,5))
library(lattice)
plots<-lapply(2:5, function(i) {xyplot(y~rdata[,i],rdata)})
print.plotlist(plots, layout=matrix(1:4, ncol=2))
to get
Otherwise you normally use a split= parameter to the print statement to place a plot in a subsection of the device. For example, you could also do
print(plots[[1]], split=c(1,1,2,2), more=T)
print(plots[[2]], split=c(1,2,2,2), more=T)
print(plots[[3]], split=c(2,1,2,2), more=T)
print(plots[[4]], split=c(2,2,2,2))

loop error - plot.new has not been called yet

I want to simulate stock paths. I have simulated 1000 paths with 22 trading days (1 starting value). Now I want to include it into my presentation, but animated, so I need the png files.
I want to create 1000 png files, starting with the first stock path, then the second and so on.
So I start with the first path, add a second to the plot, add the third and so on, so at the end I have a plot with 1000 simulations, here is my code:
for(i in 1:1000){
#jpeg(paste("1000s",i,".png",sep=""))
plot(c(1:23),matrix[,1],type="l",ylim=c(17,24))
lines(c(1:23),matrix[,i],type="l",col=i)
#dev.off()
}
Here is the problem, that each additional part disappears when the loop gets to the next value, so I tried:
plot(0,0 , xlim=c(1,23),ylim=c(17,24),xlab="",ylab="")
for(i in 1:1000){
jpeg(paste("1000s",i,".png",sep=""))
lines(c(1:23),matrix[,i],type="l",col=i)
dev.off()
}
(I know this is not a working example, but my problem is just a logical one with the loop) I get the following error message when I the last code: plot.new has not been called yet.
The matrix has 1000 columns and 23 row entries, this should be 1000 simulations of stock pathes for 22 trading days.
How can I change that the error does not appear anymore? Thanks!
Use two for loops. The outer loop will create each png/jpeg. The inner one will build up each individual plot.
for(i in 1:1000) {
jpeg(paste("1000s", i, ".png", sep=""))
plot(0, 0, xlim=c(1,23), ylim=c(17,24), xlab="", ylab="")
for(j in 1:i) {
lines(c(1:23), matrix[, j], col=j)
}
dev.off()
}
jpeg and plot both make new graphs. You just need lines calls in the loop, if you want the animation to build and not erase. One thing, lines doesn't need type = 'l'. That's it's default and the whole point of the command is that's it's default. If you wanted to plot points with it you might change the argument but otherwise just leave it out.

In R, how to prevent blank page in pdf when using gridBase to embed subplot inside plot

As explained here, it is easy to embed a plot into an existing one thanks to gridBase, even though both plots use the base graphics system of R. However, when saving the whole figure into a pdf, the first page is always blank. How to prevent this?
Here is an example:
require(gridBase)
## generate dummy data
set.seed(1859)
x <- 1:100
y <- x + rnorm(100, sd=5)
ols <- lm(y ~ x)
pdf("test.pdf")
## draw the first plot
plot.new() # blank page also happens when using grid.newpage()
pushViewport(viewport())
plot(x, y)
## draw the second plot, embedded into the first one
pushViewport(viewport(x=.75,y=.35,width=.2,height=.2,just=c("center","center")))
par(plt=gridPLT(), new=TRUE)
hist(ols$residuals, main="", xlab="", ylab="")
popViewport(2)
dev.off()
I think it's a bit of a hack but setting onefile=FALSE worked on my machine:
pdf("test.pdf", onefile=FALSE)
In searching for an answer (which I didn't really find so much as stumbled upon in the forest) I came across this post to Rhelp from Paul Murrell who admits that mixing grid and base graphics is confusing even to the Master.
A work around solution I found was to initiate the pdf file inside the for loop; then insert an if clause to assess whether the first iteration is being run. When the current iteration is the first one, go ahead and create the output device using pdf(). Put the dev.off() after closing the for loop. An quick example follows:
for(i in 1:5){
if (i == 1) pdf(file = "test.pdf")
plot(rnorm(50, i, i), main = i)}
dev.off()

Resources