Save a Plot in an Object

Save a plot in an object

base graphics draw directly on a device.

You could use

1- recordPlot

2- the recently introduced gridGraphics package, to convert base graphics to their grid equivalent

Here's a minimal example,

plot(1:10) 

p <- recordPlot()
plot.new() ## clean up device
p # redraw

## grab the scene as a grid object
library(gridGraphics)
library(grid)
grid.echo()
a <- grid.grab()

## draw it, changes optional
grid.newpage()
a <- editGrob(a, vp=viewport(width=unit(2,"in")), gp=gpar(fontsize=10))
grid.draw(a)

saving a base r plot as an object that can be plotted in a multiplot

As correctly noted by @MrFlick, the accepted answer linked here is a better approach than the %<a-% function which does not store a grid.

The code below produces the desired result.

library(ggplot2)
library(gridExtra)
library(gridGraphics)
library(grid)

Fig1 <- qplot(speed, data=cars, geom="histogram")
Fig2 <- qplot(dist, speed, data=cars, geom="point")

plot(cars$speed, cars$dist)
grid.echo()
Fig3 <- grid.grab()

Figs <- grid.arrange(Fig1, Fig2, Fig3,
layout_matrix = rbind(c(1,1,1,2,2), c(1,1,1,2,2), c(3,3,3,3,3)))

Understanding how R assigns plots as objects

Functions with the side-effect of creating a graphic plot may or may not return something. With the ggplot2 package, for instance, it returns a complex list structure with enough information and pre-defined attributes that either (1) printing it will result in a graphic object ("grob"), or (2) more layers can be added or attributes changed to this list-structure. As an example,

library(ggplot2)
gg <- ggplot(mtcars, aes(mpg,disp)) + geom_point()
str(gg, max.level=1)
# List of 9
# $ data :'data.frame': 32 obs. of 11 variables:
# $ layers :List of 1
# $ scales :Classes 'ScalesList', 'ggproto', 'gg' <ggproto object: Class ScalesList, gg>
# add: function
# clone: function
# find: function
# get_scales: function
# has_scale: function
# input: function
# n: function
# non_position_scales: function
# scales: list
# super: <ggproto object: Class ScalesList, gg>
# $ mapping :List of 2
# ..- attr(*, "class")= chr "uneval"
# $ theme : list()
# $ coordinates:Classes 'CoordCartesian', 'Coord', 'ggproto', 'gg' <ggproto object: Class CoordCartesian, Coord, gg>
# aspect: function
# backtransform_range: function
# clip: on
# default: TRUE
# distance: function
# expand: TRUE
# is_free: function
# is_linear: function
# labels: function
# limits: list
# modify_scales: function
# range: function
# render_axis_h: function
# render_axis_v: function
# render_bg: function
# render_fg: function
# setup_data: function
# setup_layout: function
# setup_panel_params: function
# setup_params: function
# transform: function
# super: <ggproto object: Class CoordCartesian, Coord, gg>
# $ facet :Classes 'FacetNull', 'Facet', 'ggproto', 'gg' <ggproto object: Class FacetNull, Facet, gg>
# compute_layout: function
# draw_back: function
# draw_front: function
# draw_labels: function
# draw_panels: function
# finish_data: function
# init_scales: function
# map_data: function
# params: list
# setup_data: function
# setup_params: function
# shrink: TRUE
# train_scales: function
# vars: function
# super: <ggproto object: Class FacetNull, Facet, gg>
# $ plot_env :<environment: R_GlobalEnv>
# $ labels :List of 2
# - attr(*, "class")= chr [1:2] "gg" "ggplot"

"Just a list."

Non-grid graphic functions sometimes employ a similar strategy. For instance, hist always returns a named list; if you use the default plot=TRUE, then it returns this list invisibly and one side-effect is the creation of a plot. With hist(..., plot=FALSE), however, the list is returned visibly and no plot is created. Similar to ggplot2's S3 method for print (ggplot2:::print.ggplot2 and friends), there is an S3 method for hist's return object (class histogram), named graphics:::plot.histogram, so if you do

h <- hist(mtcars$disp, plot = FALSE)
str(h)
# List of 6
# $ breaks : int [1:10] 50 100 150 200 250 300 350 400 450 500
# $ counts : int [1:9] 5 7 4 1 4 4 4 1 2
# $ density : num [1:9] 0.003125 0.004375 0.0025 0.000625 0.0025 ...
# $ mids : num [1:9] 75 125 175 225 275 325 375 425 475
# $ xname : chr "mtcars$disp"
# $ equidist: logi TRUE
# - attr(*, "class")= chr "histogram"

then a simple plot(h) will generate the plot. (Even if you plot it the first time with the default of h <- hist(..., plot=TRUE), you can regenerate the plot later with plot(h).)

But not all plotting functions or their accessory functions return something. lines and points, for instance, always return NULL. You cannot "capture" the output from lines and (re)apply it later.

But as far as I can tell, no base R function "returns" a plot object. grid functions might, specifically those that modify grobs.

If you want to "save" a plot itself (and not the list or components used to create it), then look into ?recordPlot, which can be run immediately after any base graphics function (including the accessory functions lines, points, etc).

How to save R base graphics as an object?

Several options from various packages:

ggplotify:

g <- as.grob(~plot(runif(10)))
grid.draw(g)

cowplot:

plot(runif(10))
p1_recorded <- recordPlot()
ggdraw(p1_recorded)

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

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?

How do I save a phytools phenogram as an image?

If anyone comes across this, I figured it out with help from Dr. Revell, the creator of phytools. It turns out, having worked almost exclusively in ggplot2, I do not really know how to use png() properly!

This is how it should go:

png(filename = "../output/APCT_phenogram_5Nov2021.png",  width = 25, 
height = 16, units = "cm", res = 300)

phenogram(tree_sub, bio01, colors = cols, fsize = 0.8, ftype = "i",
xlab = ("Relative Time"), ylab = "Mean Annual Temperature (°C)",
spread.labels = TRUE, spread.cost = c(1, 0))

dev.off()

So make a sort of empty PNG, input all the info about it, then plot whatever you're trying to plot, and then turn off the graphics device.



Related Topics



Leave a reply



Submit