convert textGrob to imageGrob/rasterGrob? - r

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)

Related

Adding text string to existing pdf doc

Is anyone aware of a way to add a text string to an existing pdf (or multiple pdfs) with R? For example, one might want to add a title in a specified position on the page or a watermark.
These similar-sounding questions aren't what I am looking for, as I would like to add text to an existing pdf - not one that I am knitting in Rmd, which would be more straightforward:
Watermark in rmarkdown
Add a 'DRAFT' watermark on pdf result of R markdown)
If (free command line) version of pdftk is an acceptable auxiliary tool, then you can automate the solution from this question in R (i.e., using the stamp operation in pdftk):
Generate PDF to experiment with:
pdf("test1.pdf")
plot(1:10,1:10)
dev.off()
Generate "watermark" overlay:
pdf("stamp.pdf")
par(fg="white")
## to match spacing etc - 'phantom' plot
plot(1:10,1:10, type="n", axes=FALSE, ann=FALSE)
par(fg="black")
text(5,5, "watermark", col=adjustcolor("gray", alpha.f=0.2), cex=5)
dev.off()
Call pdftk to do the overlay:
system("pdftk test1.pdf stamp stamp.pdf output test1S.pdf")
Results:
I think the fussy part will be getting the spacing in the overlay file the way you want it ... although you could use grid graphics, or create a zero-margin/zero-annotation plot so that the plotting area had bounds (0,1) x (0,1) ...

bokeh: How to export a grid to png with given size?

I prepared some bokeh plots to display as html.
To this end I prepared a gridplot containing the subplots, the legends and some headings. This all displays extremely nice in HTML and with sizing_mode='stretch_width' it's even kind of responsive.
webpage = gridplot([[header_col],[panel_grid_plot]], toolbar_location=None, sizing_mode='stretch_width')
show(webpage)
Now I also want to export this "webpage" to a PNG. To this end, I use
export_png(webpage, filename= png_filename, width=1800)
Unfortunately, the width parameter is ignored as the webpage is an object of type gridbox and not of type Plot. (This is checked in the bokeh/io/export.py in the method def get_layout_html())
The output is a png of a width of 800px which is kind of useless as the actual information is crushed (while the legends are nicely scaled):
Any ideas how to set the width of my PNG export to useful values?
Is there a way to convert a gridboxto a Plot?
Thanx!
You should've received a warning saying that the width argument will be ignored since you're passing into export_png something that's not a plot.
A way of achieving what you want:
webpage = gridplot(..., sizing_mode='stretch_width')
webpage.width = 1800
export_png(webpage)

Add vertical line in background in quantmod chart

How can I add vertical line to chart in quantmod that appears in the background? Consider this example:
library(quantmod)
symbol <- "AAPL"
cache <- new.env()
getSymbols(symbol, env=cache)
chartSeries(cache$AAPL, subset="last 3 months")
plot(addLines(v=10)) # Adds vertical line at tick 10.
The problem is that adding the vertical line at tick 10 now hides the wicks from the candlestick:
I also tried the function addVLine from qmao. It effectively does this:
c <- quantmod:::get.current.chob()
i <- index(c#xdata[endpoints(c#xdata, "months")])
plot(addTA(xts(rep(TRUE, length(i)), i), on=-1, col="grey"))
The result looks like this:
While I have the lines in the background now, they are super wide and pretty obtrusive. I just want them in the background in the same way the grid lines already exist there. How can I achieve this?
Note: this question resembles an existing one, but here I am asking on how to render the vertical line in the background.
I didn't look at the source code to understand why this works, but it seems to do what you want. Basically, you add the addLines call via the TA argument to chartSeries. This is generally a good thing to do anyway, since it avoids re-drawing the chart for each add* call.
chartSeries(cache$AAPL, subset="last 3 months", TA="addVo();addLines(v=10,on=-1)")

R: Bitmap output in PDF

A lot of the time, I find it very useful to output graphics with pdf() as it allows me to scroll through pages and observe subtle differences (e.g. the page numbers may correspond to a particular parameter in a simulation).
Sometimes if the plot is quite packed with information, the fact that the PDF is a vector graphic means that it takes a long time to load in a PDF reader and is useless for scrolling through pages. I could plot with png(), but this would result in many image files.
My ideal solution would be to have a device that will plot a bitmap graphic (e.g. PNG) to a PDF.
I have read that cairo_pdf() outputs to a bitmap sometimes? Or I could write something that outputs to PNG, then combines these all together into a PDF?
Any other thoughts? Or does anyone have a solution for this already?
UPDATE: have now added method based on readPNG() as suggested in comments above. It's a bit slower (3s vs 9s) and seems to result in slightly larger file sizes than ImageMagick. rasterImage() interpolation makes no difference to filesize or timing, but alters the appearance slightly. If it's FALSE, then it looks the same as ImageMagick
I have just come up with the following solution using ImageMagick. It's not perfect, but it seems to work well so far.
png2pdf <- function(name=NULL,removepngs=TRUE,method="imagemagick",pnginterpolate=FALSE){
# Run the png() function with a filename of the form name%03d.png
# Then the actual plotting functions, e.g. plot(), lines() etc.
# Then dev.off()
# Then run png2pdf() and specify the name= argument if other pngs exist in the directory
# Need to incorporate a way of dealing with non-square plots
if(is.null(name)){
names <- list.files(pattern="[.]png")
name <- unique(sub("[0-9][0-9][0-9][.]png","",names))
if(length(name)!=1) stop("png2pdf() error: Check filenames")
}else{
names <- list.files(pattern=paste0(name,"[0-9][0-9][0-9][.]png"))
}
# Can change this to "convert" if it is correctly in the system path
if(method=="imagemagick"){
cmd <- c('C:\\Program Files\\ImageMagick-6.9.0-Q16\\convert.exe',names,paste0(name,".pdf"))
system2(cmd[1],cmd[-1])
}else if(method=="readPNG"){
library(png)
pdf(paste0(name,".pdf"))
par(mar=rep(0,4))
for(i in 1:length(names)){
plot(c(0,1),c(0,1),type="n")
rasterImage(readPNG(names[i]),0,0,1,1,interpolate=pnginterpolate)
}
dev.off()
}
if(removepngs) file.remove(names)
}

Plotting images but holding visualization until instruction in 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())

Resources