Plotting images but holding visualization until instruction in R - r

I want to load two jpeg images in R consecutively but they are quite large (4000X3000 pixels)
So simply doing
library(biOps)
x <- readJpeg("image.jpg")
plot(x)
Takes a while. When the first image is displayed the user would have to fill in some observations on the image. I wanted to know if it was possible to plot the image but pause the actual visualization so as to take advantage of the time the user is filling in the data I mentioned only to display the image later, maybe upon an instruction of the user like pressing the enter key.
Can this be done?

One option is to use animation package. saveHTML will create a html file animated by SciAnimator library. You can show the first plot and stop the visualisation, go to the next, use a timer,...
ll.imgs <- list.files(Imgs_folder,patt='jpg',full=TRUE)
saveHTML({
for(i in seq_along(ll.imgs)){
x <- readJpeg("image.jpg")
plot(x) ##maybe you should try grid.raster(x) from grid package
}
}, img.name = "plots", imgdir = "plots_dir",
htmlfile = "random.html", autobrowse = FALSE,
title = "Plotting images but holding visualization until instruction",
outdir=getwd())

Related

Reading PDF plots, arranging them on a grid, save in one-page PDF using R

I have 3 R plots saved as pdf files (upper_left.pdf, upper_right.pdf, lower.pdf) as vector graphic and want to make a one-page pdf file and arrange them on it as follows:
What I have tried already
I have tried reading the pdf's using magick::image_read_pdf and appending them using magick::image_append. More specifically,
library(magick)
panel.ul <- image_read_pdf("upper_left.pdf")
panel.ur <- image_read_pdf("upper_right.pdf")
panel.l <- image_read_pdf("lower.pdf")
whole <- c(panel.ul, panel.ur) %>%
image_append() %>%
c(panel.l) %>%
image_append(stack = TRUE)
The first issue is magick::image_read_pdf imports the plot as png (if I'm right, not vector graphic though).
magick::image_append also 'works' and gives me what I want in viewer pane (in RStudio, next to Help).
I then try to save them using export::graph2pdf(whole), but it gives me a blank page.
So, if I am to use magick, there are two issues that need to be solved:
importing plots as vector graphic objects (do not know the technical term in R)
Exporting the stacked plot to a vector pdf file.
How can I solve it? thanks in advance.
You're basically done. You only need to add
plot(whole) # plot the external object generated in ImageMagick to R's plotting device
savePlot(type = "pdf") # saves the current plotting device to a pdf file.
You will find your plot in your workoing directory called "Rplot.pdf".
savePlot has many options to customize your pdf output. Make sure to check ?savePlot.
To recreate your scheme from above youll need to temporarily save the upper panel as a separate pdf before you paste it to on top of the lower panel:
whole2 <- image_append(c(panel.ul, panel.ur))
plot(whole2)
savePlot("whole2.pdf", type = "pdf")
If the upper and lower panel do not look proportionate you can use the heght and width parameters of savePlot to adjust the size of the first pdf.
panel.upr <- image_read_pdf("whole2.pdf")
final <- image_append(c(image_append(panel.upr),panel.l), stack = TRUE)
plot(final)
savePlot("final.pdf", type = "pdf")

R png()/pdf() doesn't work when running script but works if executing step by step

I'm creating a script to cluster my data in a server. I need to save the text output and the images as well. The text output works just fine but when I try to use the png() + plot() + dev.off() thing to save the plots, no image is created.
[ADDED FOR CLARIFICATION]
What I need to do is to SAVE the plot (i.e. generate an image file) in running mode. If I run the code step by step, the file is created.
I already tried to change the image format to PDF and JPG using the corresponding functions but I'm still getting no images as output when running the code as script. When stepping, it works great.
Since it takes a little while for R to render the image when I'm running step by step, I tried to add Sys.sleep(2) in between commands (code below) but nothing changed.
I think the problem might be related to the package that I'm using and the type of object it generates (library(NMF)). I looked at the documentation to see if there was something about the way the plot() function works with the type of object that the clustering algorithm generates but the text is vague:
"The result (of estim.r <- nmf(esGolub, 2:6, nrun=10, seed=123456) for example) is a S3 object of class NMF.rank, that contains a data.frame with the quality measures in column, and the values of r in row. It also contains a list of the consensus matrix for
each value of r".
"All the measures can be plotted at once with the method plot (Figure 1), and the function consensusmap generates heatmaps of the consensus matrix for each value of the rank".
There is another type of image that can be generated after the clustering runs: the consensusmap. This one works on both cases (stepping and running).
The script is pretty short. Here it is:
library(NMF)
data = read.csv('R.csv', header=TRUE, sep=";")
res1 <- nmf(data, rank=2:5, nrun=1, "brunet", "random")
# this always works
capture.output(summary(res1) ,file = "summary.txt", append = TRUE)
# this always works too
png(filename = 'consensus.png', width = 1366, height = 768, units = 'px')
consensusmap(res1)
dev.off()
# this does not work on 'running mode', only 'stepping mode'
png(filename = 'metrics.png', width = 1366, height = 768, units = 'px')
# added hoping it would fix the issue. It didn't
Sys.sleep(2)
plot(res1)
# added hoping it would fix the issue. It didn't
Sys.sleep(2)
dev.off()
The summary.txt file is generated, the consensus.png too. The metrics.png is not. What's going on here??

What is a simple way to thumbnail some plots in R Markdown/knitr?

I am using R Markdown with knitr in R Studio to create and update a simple project website to keep my colleagues up to speed with a data analysis model I am building. There are some plots on the page, which (for smaller plots) so far has worked nicely, they can see the code and the results in the same place.
However, some plots have grown very large (and must remain large to allow quick side-by-side comparison of models), and don't fit on the page very well. I've used separately uploaded pdfs (with a link on the page) for some of them. It would be nicer if there was a simple way of generating thumbnails of some of these plots, so that the user can view a small plot image, click on it and then inspect the much larger image in detail. However, if it takes a lot of manual scripting for each plot instance, I'd rather not waste time on it and just upload the couple of pdfs. A similar question here talks about package, knitrbootsrap, but I don't want to thumbnail all my plots, just a select few. The package seems to use Magnific popup, but integrating it myself in a Markdown page seems like a hassle(?). I didn't find anything in the R Markdown reference guide. Of course a one way would be to generate two plots, one tiny, which is shown, and link it to another, larger plot image/pdf that is uploaded separately - but a simpler, more automatic way would be desireable.
Hence the question - is there a simpler way to generate clickable plot thumbnails in R Markdown?
So, this is what I came up with. Add a plot hook, so that you generate a full-resolution pdf image before generating a small image in the chunk:
allow_thumbnails <- function(x, options) {
if (!is.null(options$thumb)) {
filename <- sprintf("%s.full.pdf", strsplit(basename(x), "\\.")[[1]][1])
absolute_path <- file.path(dirname(x), filename)
# generate the full resolution pdf
pdf(absolute_path, width = options$thumb$width, height = options$thumb$height)
eval(parse(text = options$code))
dev.off()
# add an html link to the low resolution png
options$fig.link = absolute_path
}
knitr:::hook_plot_md_base(x, options)
}
And then in the Rmd file, I define the size of the full-resolution image using the thumb argument:
```{r init}
knit_hooks$set(plot = allow_thumbnails)
```
```{r my_large_plot, fig.width = 15, fig.height = 15, thumb = list(width = 45, height = 45)}
my_large_plot()
```
This generates an html file with a clickable png that takes you to the pdf.

convert textGrob to imageGrob/rasterGrob?

Apologies if this is very straightforward. Actually I hope it will be!
I am trying to dynamically create images from text which I can then resize and plot (either stretched or squashed) to produce a motif-type graph.
I started out using images (which I'd generated using png() and ggplot()) and plotting them as annotation_custom()
require(ggplot2)
require(grid)
require(gridExtra)
qplot(c(0,10),c(0,10)) +
annotation_custom(rasterGrob(image=readPNG("1999.png"),x=0,y=0,height=1,width=1,just=c("left","bottom")),
xmin=0,xmax=5,ymin=0,ymax=7.5)
to produce:
This is fine, but it's awkward to create the images dynamically if they are not the same size, using png(), plus it's clunky to persist them to file, so I tried to see if I could use a textGrob:
myText<-"1000"
myTextGrob<-textGrob(myText,just=c("left","bottom"),gp=gpar(fontsize="100",col="red",fontfamily="Showcard Gothic"))
qplot(c(0,10),c(0,10))+annotation_custom(myTextGrob,0,0,0,0)
and got this, which is fine, except....
...it doesn't seem possible to stretch & skew it in the same way as a rasterGrob so my question is - is it possible to create the textGrob and coerce it to a rasterGrob? Or is there another solution which will let me skew/stretch the textGrob?
Thanks in advance!
It doesn't seem easy without creating temporary files. Instead of raster files, you might use vector paths with the grImport package. There are two options to import text,
as a path; it works (example below), but there's no obvious way to bypass the ps to xml conversion step with intermediate files
as a text string; the xml is much shorter in this case, and could be created directly from R, but unfortunately I couldn't find a way to transform the two axes independently.
library(grImport)
scale_text <- function(text="hello world", scale=4, tmp=tempfile()){
tmp.ps <- paste0(tmp, ".ps")
tmp.xml <- paste0(tmp, ".xml")
string.ps <- paste0('%!PS
/Courier % name the desired font
20 selectfont % choose the size in points and establish
% the font as the current one
1 ', scale, ' scale % scale axis
72 500 moveto % position the current point at
% coordinates 72, 500 (the origin is at the
% lower-left corner of the page)
(', text, ') show % stroke the text in parentheses
showpage % print all on the page
')
cat(string.ps, file=tmp.ps)
PostScriptTrace(tmp.ps, tmp.xml)
readPicture(tmp.xml)
}
hello <- scale_text()
grid.newpage()
grid.picture(hello)

R save images to create animation of plot incrementally generated with large number of points

I'm trying to create an animation based on a scatter plot that is incrementally built up over time. The use case is that I have a database of about 2 million points with timestamps for each, and want to generate frames that show all the points at or before a specific date.
Without saving the images, I'm able to do this by first calling plot(), and then having a for loop that incrementally draws the data for each successive day using the points() function.
When I try to save images using the code below, I get an error of "plot.new has not been called yet". As I understand, dev.off() is needed to save image, but that also closes the device that is being drawn to. Is there a way to get around this? Having to re-plot the data for every frame isn't much of an option due to the size of the data.
plot(info$lon, info$lat, xlim=c(0,30), ylim=c(30,60))
for (i in c(1:length(allDates))){
filename=paste(sprintf('%05d', i), ".png", sep="")
png(filename=fileName)
# (code that gets the data for a particular date via a database query)
points(info$lon, info$lat, cex=0.1)
dev.off()
}
UPDATE:
The comment by #roman-lustrik about ggsave() was what I was looking for, and results in the code below:
plotObj = ggplot(...) + geom_point() + xlim(...) + ylim(...)
for (i in c(1:length(allDates))){
filename=paste(sprintf('%05d', i), ".png", sep="")
# (code that gets the data for a particular date via a database query)
plotObj = plotObj + geom_point(data=info, aes(x=lon, y=lat), size=0.5)
print(plotObj)
ggsave(filename=filename, width=6, height=6)
}
However, this is still a bit slow, so my current solution to render images quickly is to use the code similar to the original, but where I just use plot() to render frames with data for a single date (using a transparent background). To progressively stack up the images, I then use a bash script which uses the imagemagick convert -composite command to blend two images together. This blended image is then blended with the image from the next date, and so on, until the final image shows all of the data:
#!/bin/bash
for i in $files
do
convert $prevFile $i -composite ./stackedImages/$i
prevFile=./stackedImages/$i
done
If I have understood, you want to get several png files with different number of points on it, and with the first points created by plot(info$lon, info$lat, xlim=c(0,30), ylim=c(30,60)).
You can do that instead :
temp1 <- info$lon
temp2 <- info$lat
for (i in c(1:length(allDates))){
filename=paste(sprintf('%05d', i), ".png", sep="")
png(filename=fileName)
plot(temp1, temp2, xlim=c(0,30), ylim=c(30,60))
# (code that gets the data for a particular date via a database query)
points(info$lon, info$lat, cex=0.1)
dev.off()
temp1 <- c(temp1,info$lon)
temp2 <- c(temp2,info$lat)
}

Resources