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) print
ing 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
Rstudio Does Not Display Any Output in Console After Entering Code
Use Dynamic Name For New Column/Variable in 'Dplyr'
Split Delimited Strings in a Column and Insert as New Rows
Find Complement of a Data Frame (Anti - Join)
Grouping Functions (Tapply, By, Aggregate) and the *Apply Family
Reshaping Multiple Sets of Measurement Columns (Wide Format) into Single Columns (Long Format)
Extract Rows for the First Occurrence of a Variable in a Data Frame
Sum Across Multiple Columns With Dplyr
How to Declare a Vector of Zeros in R
Add Row to a Data Frame With Total Sum for Each Column
Removing Columns That Are All 0
What Are the Differences Between "=" and "≪-" Assignment Operators
How Split Column of List-Values into Multiple Columns
How to Sort a Data Frame by Alphabetic Order of a Character Variable in R
How to Force R to Use a Specified Factor Level as Reference in a Regression
Ggplot2 Stacked Bar Chart - Each Bar Being 100% and With Percenage Labels Inside Each Bar