Match ODFWeave and ggplot2 image resolution/size - r

I'm creating charts using ggplot2 inside ODFWeave code chunks. I am setting the ODFWeave dimensions to 5x5in, but the graphs are being created at 480x480 px which looks like a default. How can I make these larger and match them to the ODF size to get a good quality print?
ODFWeave Options:
imageDefs <- getImageDefs()
imageDefs$dispWidth <- 5
imageDefs$dispHeight<- 5
setImageDefs(imageDefs)
Code snippet in weave doc:
<<ClosureGraph, echo = FALSE, fig = TRUE>>=
#function returns a ggplot obj.
p<-closuresbyperiod()
print(p)
#

Thanks to the package manager for pointing out that we can use plotWidth and Height to do this, e.g:
imageDefs <- getImageDefs()
imageDefs$dispWidth <- 4
imageDefs$dispHeight<- 4
imageDefs$plotWidth <- 800
imageDefs$plotHeight<- 800
setImageDefs(imageDefs)
This is done before issues the odfWeave command

Related

How to store r ggplot graph as html code snippet

I am creating an html document by creating various objects with ggplotly() and htmltools functions like h3() and html(). Then I submit them as a list to htmltools::save_html() to create an html file.
I would like to add ggplot charts directly as images, rather than attaching all the plotly bells and whistles. In the end, I will create a self-contained html file (no dependencies), and the plotly stuff would make that file excessively large.
Is there some function that converts a ggplot object into some html-type object? Or do I have to save the ggplot as a .png file, then read the .png file into some object that I add to the list in the save_html() function?
My R code looks something like this:
library("tidyverse")
library("plotly")
library("htmltools")
HTMLOut <- "c:/Users/MrMagoo/My.html")
df <- data.frame(x=1:25, y=c(1:25*1:25))
g7 <- ggplot(df,aes(x=x, y=y)) + geom_point()
p7 <- ggplotly(g7) # I would like to use something other than ggplotly here. Just capturing the ggplot as an image would be fine.
# create other objects to add to the html file
t7 <- h2(id="graph7", "Title for graph #7")
d7 <- p("description of graph 7")
save_html(list(t7, p7, d7), HTMLOut)
# of course, the real code has many more objects in that list – more graphs, text, tables, etc.
I would like to replace the plotly object (p7) with something that just presents g7 in a way that would not cause an error in the save_html function.
I had hoped to find a function that could directly Base64 encode a ggplot object, but it seems that I first need to output the 'ggplot' object as a .png file (or SVG, per Teng L, below), then base64-encode it. I was hoping there was a more direct way, but I may end up doing that, as in https://stackoverflow.com/a/33410766/3799203 , ending it with
g7img <- "<img src=\"data:image/png;base64,(base64encode string)\""
g7img <- htmltools::html(g7img)
If you want to save the plot as a dynamic plotly graph, you could use htmlwidgets::saveWidget. This will produce a stand-alone html file.
Here is a minimal example:
library(tidyverse);
library(plotly);
library(htmlwidgets);
df <- data.frame(x = 1:25, y = c(1:25 * 1:25))
gg <- ggplot(df,aes(x = x, y = y)) + geom_point()
# Save ggplotly as widget in file test.html
saveWidget(ggplotly(gg), file = "test.html");
I ended up generating a temparory image file, then base64 encoding it, within a function I called encodeGraphic() (borrowing code from LukeA's post):
library(ggplot2)
library(RCurl)
library(htmltools)
encodeGraphic <- function(g) {
png(tf1 <- tempfile(fileext = ".png")) # Get an unused filename in the session's temporary directory, and open that file for .png structured output.
print(g) # Output a graphic to the file
dev.off() # Close the file.
txt <- RCurl::base64Encode(readBin(tf1, "raw", file.info(tf1)[1, "size"]), "txt") # Convert the graphic image to a base 64 encoded string.
myImage <- htmltools::HTML(sprintf('<img src="data:image/png;base64,%s">', txt)) # Save the image as a markdown-friendly html object.
return(myImage)
}
HTMLOut <- "~/TEST.html" # Say where to save the html file.
g <- ggplot(mtcars, aes(x=gear,y=mpg,group=factor(am),color=factor(am))) + geom_line() # Create some ggplot graph object
hg <- encodeGraphic(g) # run the function that base64 encodes the graph
forHTML <- list(h1("My header"), p("Lead-in text about the graph"), hg)
save_html(forHTML, HTMLOut) # output it to the html file.
I think what you want may be close to one of the following:
Seems you are creating an HTML report but hasn't checked out RMarkdown. It comes with Base64 encode. When you create an RMarkdown report, pandoc automatically converts any plots into an HTML element within the document, so the report is self-contained.
SVG plots. This is less likely to be what you might want, but SVG plots are markup-language based and may be easily portable. Specify .svg extension when you use ggsave() and you should be getting an SVG image. Note that SVG is an as-is implementation of the plot, so if can be huge in file size if you have thousands of shapes and lines.
This is an extension to the Maurits Evers post. In this answer I'm showing how to combine multiple plotly plots in the same html file in an organized fashion:
library("plotly")
library("htmltools")
# a small helper function to avoid repetition
my_func <- function(..., title){
## Description:
## A function to add title to put multiple gg plotly objects under a html heading
##
## Arguments:
## ...: a list of gg objects
## title: a character vector to specify the heading text
# get the ... in list format
lst <- list(...)
# create the heading
tmp_title <- htmltools::h1(title)
# convert each ggplot to ggplotly and put them under the same div html tag
tmp_plot <- lapply(lst, ggplotly) |>
htmltools::div()
# return the final object as list
return(list(tmp_title, tmp_plot))
}
# a toy data
df <- data.frame(x = 1:25, y = c(1:25 * 1:25))
# the ggplot object using the toy data
gg <- ggplot(df,aes(x = x, y = y)) + geom_point()
# put everything in order
final_list <- list(my_func(obj = list(gg, gg, gg), title = "The first heading"),
my_func(obj = list(gg, gg), title = "The second heading"))
# write to disk as a unified HTML file
htmltools::save_html(html = final_list,
file = "index.html"))
Disclaimer: I specifically did this to avoid using widgetframe R package and to be completely on par with the documentation of plotly-r. You can read the link if you are comfortable with adding extra dependency and extra abstraction layer. I prefer to use packages if and only if necessary. :)

R: Making Bigger Graphs when using facet_wrap()

I'm having some trouble visualizing some data in an R Markdown document. I'm attaching a picture for your reference.
I would like the graphs produced to be larger, and would expect the HTML page to allow for these graphs to be spread out, but they are all coming back "squished"
g <- ggplot(item_loc_metrics, aes(capc_ssp_ratio, avg_wk_bkrm_eoh)) + geom_point(color="firebrick")
g
I run this and it returns a nicely formatted graph:
This snippet of code works fine, but I would like to cut this same graph 60+ times based on the store I'm looking at. I've tried to to do that with this bit:
g2 <- ggplot(item_loc_metrics, aes(capc_ssp_ratio, avg_wk_bkrm_eoh)) + geom_point(color="firebrick") + facet_wrap(~CO_LOC_N, ncol=5, scales = "fixed", shrink = FALSE)
g2
I end up then getting something that looks like this:
To let this question have an answer, I add my two cents.
You can increase fig.height and fig.width(as suggested in the comment) and set ncol to one.

How does R's tikzDevice deal with raster images?

I have read, if tikz takes a raster image it is to be stored as png. Having that, tikz produces the rest of the graph around it and include the raster image in the final tex-file back again.
Now I have the following:
pic <- T
if(pic)
{
tikz(file=paste(plotpath,"Rohdaten_S1_S2_D21.tex",sep=""),width=width,height=height,engine = "pdftex",)
#png(filename=paste(plotpath,"Rohdaten_S1_S2_D6.png",sep=""),width=width,height=height,res=res,units="in")
par(mfrow=c(2,1),mar=c(1.1,3,2,0),mgp=c(1.5,0.5,0),ps=f.size,cex=1,xaxt="n")
}
if(!pic) par(mfrow=c(2,1),mar=c(1,4,3,0))
for(i in 1:2)
{
x <- sensors[[i]]$time
y <- sensors[[i]]$depth
z <- sensors[[i]]$velo
image(x,y,z)
# plot.image(x,y,z
# ,xlim=c(max(x)-400,max(x)),zlim=2*c(-1,1)
# ,xlab="",ylab="$d/\\mathrm{m}$",zlab="$v/(\\mathrm{mm/s})$"
# ,z.adj=c(0,0),ndz=5,z.cex=1
# )
abline(v=(1:10)/0.026+par("usr")[1],lty=2)
if(!pic) abline(h=(1:floor(max(y/0.02)))*0.02)
mtext(text=paste("Sensor",i),side=3,line=0.1,adj=0)
par(mar=c(3,3,0.1,0),xaxt="s")
}
title(xlab="t/s")
if(pic) dev.off()
even the simple image() function will produce a 100MB large .tex file.
No png is produced, everything is in the .tex file?!
What am I doing wrong? Is there a switch to be set TRUE? What do I have to do to put the rasterimage apart from the nice looking text.
Thank you for your help.
The solution is quite simple, but not obvious.
the image()-function in R produces vector graphics in the first
instance. There is a switch image(...,useRaster = T) with which
one can force the image()-function to produce raster graphics.
the image()-function aspects a regular grid (quadratic pixels). Otherwise an error occurs.
How to get a regular grid?
Suppose you have an image with the coordinates x[],y[] and the scalar matrix z[,]. Then the re-sampled regular grid can be calculated:
x.new<-seq(min(xlim),max(xlim),length.out=dim.max[1])
y.new<-seq(min(ylim),max(ylim),length.out=dim.max[2])
z<-apply(z,2,function(y,x,xout) return(approx(x,y,xout=xout+min(diff(x))/2,method="constant",rule=2)$y),x,x.new)
z<-t(apply(z,1,function(y,x,xout) return(approx(x,y,xout=xout+min(diff(x))/2,method="constant",rule=2)$y),y,y.new))
tikz(file ='a.tex',width = 2, height = 2)
image(x,y,z,useRaster = T)
dev.off()
The important things are the method = "constant" and the rule = 2 statements in the approx()-function. These enables a "shifting" to the regular grid.
Applying all this and tikz() will split the picture in a a.tex-file and a a_ras1.png-file.
I hope this will help sombody programming R and using tikzDevice to produce pictures for tex documents.

Exporting rgl.snapshot and rgl.postscript fails

I am currently using the rgl package for some data representation.
Here's my command
mypath("directory")
png(file=mypath, res=600, width=10.5, height= 10.5,units="in",bg = "transparent")
require(rgl)
set.seed(1)
df <- data.frame(replicate(4,sample(1:200,1000,rep=TRUE)))
colnames(df) <- c("var1","var2","var3","var4")
plot3d(x=df$var1, y=df$var2, z=df$var3, col=as.numeric(df$var4), size=0.5, type='s',xlab="var1",ylab="var2",zlab="var3")
rgl.snapshot(mypath)
The command above works and produces a tiny image, which I wasn't able to make bigger, or increase its resolution (to 600).
I have also tried to export a pdf using:
rgl.postscript(mypath, fmt="pdf")
but when I execute the command R goes into a "not responding" state.
Can somebody please show me how to properly export the file? I would prefer the have the PNG with the resolution 600 dpi.
Cheers,
A solution can be to set the size of the window using open3d() :
require(rgl)
set.seed(1)
df <- data.frame(replicate(4,sample(1:200,1000,rep=TRUE)))
colnames(df) <- c("var1","var2","var3","var4")
open3d(windowRect=c(100,100,700,700))
plot3d(x=df$var1, y=df$var2, z=df$var3, col=as.numeric(df$var4), size=0.5, type='s',xlab="var1",ylab="var2",zlab="var3")
rgl.snapshot(<path to png file>)
May be someone need. I used the following combination for persp3Drgl:
persp3Drgl(...)
par3d( windowRect=c( 0,0,100,100 ) )
snapshot3d( file.path(plotDir, "3D.png"), top = TRUE )
Without top = TRUE it got failed.

r multiple graphs on a single jpeg

I have run into the following problem and I would appreciate if someone could give me some input.
I would like to export multiple figures to a single jpeg file. I first create a graphics lattice and then I export. My main issue is that it works with the pdf and not the jpeg. Any ideas?
Thank you
#set the windows of the frames
par(mfcol=c(3,2))
#create the jpeg file
jpeg(filename=names(a1),".jpg",sep=""),
quality=100,
width=1024,
height=768)
#plot 1
plot(a1,b1)
#plot 2
plot(a1,b2)
#plot 3
plot(a1,b3)
#plot 4
plot(a2, c1)
#plot 5
plot(a2, c2)
#plot 6
plot(a2, c3)
#dev.off shuts down the specified (by default the current) graphical device
#here it passes the picture to the file
dev.off()
It is not clear whether you want multiple 1024x768 images in a single jpeg file - which doesn't make sense - are whether you want a single jpeg image containing the 6 plots.
As I said, JPEGs are not a multi-page format, unlike a PDF. Hence you can get R to export to multiple JPEG files but not have all the separate figures in one JPEG.
R's devices allow for wildcards in the filenames, so if you want the six plots exported to files foo001.jpeg, foo002.jpeg, foo00x.jpeg then you can use the following
jpeg(filename = "foo%03d.jpeg", ....)
.... # plotting commands here
dev.off()
What happens if you do multiple plots without the wildcard/placeholder is document in say ?jpeg:
If you plot more than one page on one of these devices and do not
include something like ‘%d’ for the sequence number in ‘file’, the
file will contain the last page plotted.
Devices that handle multiple pages because the underlying file format allows it can take multiple plots into the single file as there is makes sense, e.g. pdf() and postscript(). Those devices have argument onefile which can be used to indicate if multiple plots in a single file are required.
However, the par(mfcol=c(3,2)) makes me think you want a 3x2 set of plots in the same device region. That is allowed, but you need to call par() after you open the jpeg() device, not before. What your code, as shown, does is split the active device into 3x2 plotting regions and then opens a new device which picks up the default parameters, not the ones you set on the device active before you called jpeg(). This is illustrated below:
> plot(1:10)
> dev.cur()
X11cairo
2
> op <- par(mfrow = c(3,2))
> jpeg("~/foo.jpg")
> par("mfrow")
[1] 1 1
> dev.off()
X11cairo
2
> par("mfrow")
[1] 3 2
Hence you want perhaps wanted something like:
jpeg(filename=names(a1),".jpg",sep=""), quality=100,
width=1024, height=768)
op <- par(mfcol=c(3,2))
#plot 1
plot(a1,b1)
#plot 2
plot(a1,b2)
#plot 3
plot(a1,b3)
#plot 4
plot(a2, c1)
#plot 5
plot(a2, c2)
#plot 6
plot(a2, c3)
par(op)
dev.off()
?
The corrected code
#data
a1<-seq(1,20,by=1)
b1<-seq(31,50,by=1)
b2<-seq(51,70,by=1)
b3<-seq(71,90,by=1)
#create the jpeg file
jpeg(filename="a.jpg",
quality=100,
width=1024,
height=768)
#set the create the frames
par(mfcol=c(3,1))
#plot the graphs
plot(a1,b1)
plot(a1,b2)
plot(a1,b3)
#par(op)
#dev.off shuts down the specified (by default the current) graphical device
#here it passes the picture to the file
dev.off()

Resources