How to plot a high resolution image in ggplot without saving the file? - r

I am working on a restricted data online which I do not have access to. I can still get the outputs of my codes, but I cannot access any saved files of the outputs. Options like ggsave and other ones permit to have high-resolution quality figures, but then I cannot use these as I do not have access to the folders. Is there another way to produce these figures without having to save them? I can have access to the figures that plot in the R interface.
Let's suppose we use this code:
plot= ggplot(mtcars, aes(displ, hwy)) +
geom_point() +
geom_smooth()
If we type plot, R will display the graph. Is there a way to modify its resolution, length and width? and then to type plot and get these modifications?

For running remote scripts (e.g. via ssh) that output a svg representation of a plot, you might consider using repr.
Here's an example code (hack) that can work in non interactive mode on linux servers:
sink(file = "/dev/null") # suppresses all the output
library(ggplot2)
library(repr)
png(filename = "/dev/null") # start an arbitrary device. (it does not really matter)
dev.control("enable") #set this to allow recording from the device
g <- ggplot(mtcars, aes(disp, hp)) +
geom_point() +
geom_smooth()
print(g)
p <- recordPlot() #record it
dev.off() #close the device
sink() #restore the output
cat(repr_svg(p), width = 7, height = 7)) #print out the svg
Save the script to e.g. example_script.R, then run in a terminal
cat example_script.R | ssh myuser#myhost Rscript '-' > example.svg
This will save the results in the file example.svg

Related

ggplot2: CairoSVG changes point size

I build scatterplots using ggplot2 in R. I then want to save them as svg files with Cairo::CairoSVG. It seems to work fine except for the point size, which is enlarged in the resulting .svg file.
Here comes some example code:
library (ggplot2)
my_plot <- ggplot(mpg, aes(cty, hwy)) +
geom_point(size = 0.5)
x11 (width = 6, height = 6)
my_plot
Cairo::CairoSVG (file = "my_path",
width = 6, height = 6)
print (my_plot)
dev.off()
And this is what I get: on the right hand, the plot printed in R and on the left side the saved .svg-file opened in Inkscape. It looks fine except for the point size, which is a pity. Are there any ideas on how to get the right point-size? I tried different point sizes and also shapes, with similarly unmatched results.
Note that I seek to stick with Cairo::CairoSVG, beacuse in the final plots I wish to use custom fonts which are printed nicely with Cairo::CairoSVG. Any help is appreciated.
EDIT: I am working on a Windows machine.
Preliminary remark: when you pass width = 6, height = 6 in the Cairo::CairoSVG() parameters, you provide potentially different parameters (resolution and display) from the ones used in the RStudio plot panel.
To get the exact same image than the one rendered in the panel as well as using Cairo, you can use this alternative (dev.size('px') returns the dimensions of the current plot panel):
library (ggplot2)
my_plot <- ggplot(mpg, aes(cty, hwy)) +
geom_point(size = 0.5)
my_plot
mirror <- recordPlot()
png(filename = "mypath",
width = dev.size('px')[1]/96,
height = dev.size('px')[2]/96,
res = 96, # base RStudio resolution
units = "in",
type = "cairo") # calls CairoSVG
replayPlot(mirror)
dev.off()
(Note : I prefer the use of png() rather than ggsave() because it will save the entire last plot. I have observed that ggsave() would save only the last facet of a grid, for example)

R open plotly in standalone window

I would like to display a plotly plot object in a standalone window that behaves similarly to the window that pops up using the base R plot() function.
Using a basic example from the plotly website:
library(ggplot2)
library(plotly)
d <- diamonds[sample(nrow(diamonds), 1000), ]
p <- ggplot(data = d, aes(x = carat, y = price)) +
geom_point(aes(text = paste("Clarity:", clarity))) +
geom_smooth(aes(colour = cut, fill = cut)) + facet_wrap(~ cut)
p2 <- ggplotly(p)
The p2 object is an htmlwidget object and I get some control over its display using the sizingPolicy element as described here. However, I can't find anything that allows me to set the viewer/browser to something other than my current browser (as a new tab) or within RStudio.
Ideally, I'd like to avoid applications outside of R packages to launch a separate window from within R. However, I would also be happy with figuring out how to granularly control browser output to display p2 as a new window in kiosk or app mode (see the answers to this question for some examples of kiosk/app mode).
Edit: Although I mentioned RStudio when discussing some of the options that I was able to find, I am talking about using R from a simple console. That said, granular display options should hopefully be independent of the user interface.
I have a working solution, but I'll be happy to change the accepted answer if someone has anything better.
I defined a print function that can be used to launch a custom browser command for an htmlwidget object. In this case, I used chromium-browser -app=..., but the overall approach should be general.
print_app <- function(widget) {
# Generate random file name
temp <- paste(tempfile('plotly'), 'html', sep = '.')
# Save. Note, leaving selfcontained=TRUE created files that froze my browser
htmlwidgets::saveWidget(widget, temp, selfcontained = FALSE)
# Launch with desired application
system(sprintf("chromium-browser -app=file://%s", temp))
# Return file name if it's needed for any other purpose
temp
}
Combining with the previous example:
library(ggplot2)
library(plotly)
d <- diamonds[sample(nrow(diamonds), 1000), ]
p <- ggplot(data = d, aes(x = carat, y = price)) +
geom_point(aes(text = paste("Clarity:", clarity))) +
geom_smooth(aes(colour = cut, fill = cut)) + facet_wrap(~ cut)
p2 <- ggplotly(p)
print_app(p2)
It seems like htmlwidgets normally uses the html_print function from htmltools, which in turn selects the browser to use via getOption("viewer", utils::browseURL), which bakes in a lot of the browser selection options -- making it challenging to change.
The idea for saving the html file locally came from this plotly issue: saving plotly plots locally?.
If you are using MacOS, change this line in #ssokolen's answer
# Launch with desired application
system(sprintf("chromium-browser -app=file://%s", temp))
to
system(sprintf("open -a 'google chrome' /%s", temp))
Works in zsh in MacOs Catalina with the Intellij R plugin.

Saving two ggplots in grid.arrange to eps file format

I am working in RStudio and have two ggplots, call them plot1 and plot2. I would like to arrange them one above the other and save into eps format. I have read the following posts on the topic:
Export a graph to .eps file with R
Saving grid.arrange() plot to file
Side-by-side plots with ggplot2
I have tried multiple methods which I list below, all of which have failed. Most revolve around using gridarrange.
1) My initial method was to run:
setEPS()
postscript("Figure1.eps",width=11.5,height=16)
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
dev.off()
Similar to link 1 but with grid.arrange. There are no errors in R and an EPS file appears in my directory, however the filesize is small and I cannot open it in a file viewer, it appears to be corrupted for some reason.
2) My second attempt used ggsave:
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
ggsave("Figure1.eps", p)
This saves only the second plot. Then try suggestions from comments from link 2:
The code
p <- arrangeGrob(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
grid.draw(p) # interactive device
ggsave("Figure1.eps", p)
gives output: Error in ggsave("saving.eps", p) : plot should be a ggplot2 plot
The code
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
p<-arrangeGrob(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
ggsave("Figure1.eps", p)
gives output: Error in ggsave("saving.eps", p) : plot should be a ggplot2 plot
The code
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
ggsave <- ggplot2::ggsave; body(ggsave) <- body(ggplot2::ggsave)[-2]
p<-arrangeGrob(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
ggsave("Figure1.eps", p)
gives output:
Saving 8.28 x 9.07 in image
TableGrob (2 x 1) "arrange": 2 grobs
z cells name grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (2-2,1-1) arrange gtable[layout]
In this final case, a file appears in the directory but it is small and cannot be opened.
3) My final attempt is just to use the command
png("Figure1.eps",height=11.5,width=16,units="cm",res=600)
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
dev.off()
This produces a 'eps' file and is of a large size, and can be opened, however I am unsure if to trust it. Why would the png command be able to create an eps file? I have a feeling it's just a png file but masked as an eps somehow if that is possible. Is there a way to check the files format?
EDIT: Code to create plots for which the above code can be ran.
data1<-data.frame(a=c(1,2,3,4,0.5,1,1.5,2,0.5,1,3,4),b=c(1,2,3,4,1,2,3,4,1,2,3,4),
c=c('graph1','graph1','graph1','graph1','graph2','graph2','graph2','graph2','graph3','graph3','graph3','graph3'))
data2<-data.frame(a=c(10,20,25,40,13,14,25,37,2,20,34,35),b=c(1,2,3,4,1,2,3,4,1,2,3,4),
c=c('graph1','graph1','graph1','graph1','graph2','graph2','graph2','graph2','graph3','graph3','graph3','graph3'))
plot1<-ggplot(data1, aes(x=b,y=a)) +
geom_line() +
geom_point(size=2.5) +
facet_wrap(~c, scales="fix") +
scale_x_continuous(limits=c(1,4),labels=c("Zero","Low","Med","High")) +
ylab("ylab1") +
coord_cartesian(ylim=c(0,4)) +
theme(legend.position="none",axis.title.x=element_blank(), panel.margin.x=unit(1.1, "lines"))
plot2<-ggplot(data2, aes(x=b,y=a)) +
geom_line() +
geom_point(size=2.5) +
facet_wrap(~c, scales="fix") +
scale_x_continuous(limits=c(1,4),labels=c("Zero","Low","Med","High")) +
coord_cartesian(ylim=c(0,40)) +
xlab("level of correlation") +
ylab("ylab2") +
theme(legend.position="none",axis.title.x=element_blank(), panel.margin.x=unit(1.1, "lines"))
EDIT: I have also now realised that
setEPS()
postscript("TestFig3.eps")
plot1
dev.off()
which should just simply create an eps file (no grid.arrange involved) also does not work. A file is created and no error message in R, but it is corrupted in some way.
Ideally I would like an
eps()
grid.arrange()
dev.off()
but ?eps provides no packages.
I realise there is already quite a lot of chat about this, however I have not been able to source a solution from it all.

Ggplot does not show plots in sourced function

I've been trying to draw two plots using R's ggplot library in RStudio. Problem is, when I draw two within one function, only the last one displays (in RStudio's "plots" view) and the first one disappears. Even worse, when I run ggsave() after each plot - which saves them to a file - neither of them appear (but the files save as expected). However, I want to view what I've saved in the plots as I was able to before.
Is there a way I can both display what I'll be plotting in RStudio's plots view and also save them? Moreover, when the plots are not being saved, why does the display problem happen when there's more than one plot? (i.e. why does it show the last one but not the ones before?)
The code with the plotting parts are below. I've removed some parts because they seem unnecessary (but can add them if they are indeed relevant).
HHIplot = ggplot(pergame)
# some ggplot geoms and misc. here
ggsave(paste("HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
HHIAvePlot = ggplot(AveHHI, aes(x = AveHHI$n_brokers))
# some ggplot geoms and misc. here
ggsave(paste("Average HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
I've already taken a look here and here but neither have helped. Adding a print(HHIplot) or print(HHIAvePlot) after the ggsave() lines has not displayed the plot.
Many thanks in advance.
Update 1: The solution suggested below didn't work, although it works for the answer's sample code. I passed the ggplot objects to .Globalenv and print() gives me an empty gray box on the plot area (which I imagine is an empty ggplot object with no layers). I think the issue might lie in some of the layers or manipulators I have used, so I've brought the full code for one ggplot object below. Any thoughts? (Note: I've tried putting the assign() line in all possible locations in relation to ggsave() and ggplot().)
HHIplot = ggplot(pergame)
HHIplot +
geom_point(aes(x = pergame$n_brokers, y = pergame$HHI)) +
scale_y_continuous(limits = c(0,10000)) +
scale_x_discrete(breaks = gameSizes) +
labs(title = paste("HHI Index of all games,",year,"Finals"),
x = "Game Size", y = "Herfindahl-Hirschman Index") +
theme(text = element_text(size=15),axis.text.x = element_text(angle = 0, hjust = 1))
assign("HHIplot",HHIplot, envir = .GlobalEnv)
ggsave(paste("HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
I'll preface this by saying that the following is bad practice. It's considered bad practice to break a programming language's scoping rules for something as trivial as this, but here's how it's done anyway.
So within the body of your function you'll create both plots and put them into variables. Then you'll use ggsave() to write them out. Finally, you'll use assign() to push the variables to the global scope.
library(ggplot2)
myFun <- function() {
#some sample data that you should be passing into the function via arguments
df <- data.frame(x=1:10, y1=1:10, y2=10:1)
p1 <- ggplot(df, aes(x=x, y=y1))+geom_point()
p2 <- ggplot(df, aes(x=x, y=y2))+geom_point()
ggsave('p1.jpg', p1)
ggsave('p2.jpg', p2)
assign('p1', p1, envir=.GlobalEnv)
assign('p2', p2, envir=.GlobalEnv)
return()
}
Now, when you run myFun() it will write out your two plots to .jpg files, and also drop the plots into your global environment so that you can just run p1 or p2 on the console and they'll appear in RStudio's Plot pane.
ONCE AGAIN, THIS IS BAD PRACTICE
Good practice would be to not worry about the fact that they're not popping up in RStudio. They wrote out to files, and you know they did, so go look at them there.

Plotting to a file from a function in R

Background
Hey everyone!
I'm new to using R, and became interested in using it after having a team member give a tutorial of how useful it can be in an academic setting.
I am trying to write a script to automatically read my data from multiple files and then plot the resultant graphs to multiple files, so that they can be easily added to a manuscript (PowerPoint, latex, etc.)
Problem
I have found that the following code will allow me to produce a graph
p = qplot(factor(step), y, data=x, colour=c))
p = p + theme_bw()
# etc...
wrapping this around a png call will allow me to output the plot to a PNG:
png("test.png")
p = qplot(factor(step), y, data=x, colour=c))
p = p + theme_bw()
# etc...
p
dev.off()
I wanted to put the graph creation into a function so that I can create graphs and consequent seperate PNGs. So I put everything into a function:
func <- function()
{
png("test.png")
p = qplot(factor(step), y, data=x, colour=c))
p = p + theme_bw()
# etc...
p
dev.off()
}
If I call func() A PNG is created, but it is empty. Is there any specific reason why I can do this without the function but can't when I'm calling it from a function?
When using ggplot2 or lattice non-interactively (i.e. not from the command-line), you need to explicitly print() plots that you've constructed. So just do print(p) in the final line of your code, and all should be fine.
This is unintuitive enough that it's one of the most frequent of all FAQs.

Resources