Guardar un gráfico en un objeto

83

En ggplot2, uno puede guardar fácilmente un gráfico en un objeto R.

p = ggplot(...) + geom_point()      # does not display the graph
p                                   # displays the graph

La función estándar plotproduce el gráfico como una función nula y devuelve NULL.

p = plot(1:10)     # displays the graph
p                  # NULL

¿Es posible guardar un gráfico creado por ploten un objeto?

Remi.b
fuente
plotes genérico, y diferentes plotmétodos devuelven tales objetos, hasta donde yo sé. plot.default, sin embargo, de hecho regresa NULL.
Konrad Rudolph
¿Su objetivo es poder volver a trazar su gráfico solo escribiendo pdespués de guardarlo como un objeto? ¿O le gustaría guardarlo como un objeto que luego podría alterar sus valores, por ejemplo?
LyzandeR
Es posible que desee superponer otros gráficos sobre el gráfico guardado, pero no pretendo modificar el gráfico que se ha creado y guardado. ¿Respondí a tu pregunta? Thks
Remi.b
@ Remi.b Lo hace gracias. Publiqué una solución que podría ayudar.
LyzandeR

Respuestas:

95

los gráficos base se dibujan directamente en un dispositivo.

Podrías usar

1- recordPlot

2- el gridGraphicspaquete introducido recientemente , para convertir gráficos base a su equivalente en cuadrícula

Aquí hay un ejemplo mínimo,

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)
baptiste
fuente
1
No me queda claro: ¿son (1) y (2) métodos separados para lograr el mismo objetivo, o son necesarios dos pasos para responder a la pregunta del OP?
NLi10Me
@ NLi10Me 2 métodos diferentes.
zx8754
Si lo intento saveRDS(object = p, file = "p.Rds"), luego cargo una nueva sesión R, la ejecuto p <- readRDS(file = "p.Rds")seguido de p, aparece un mensaje de error que dice Error in replayPlot(x) : loading snapshot from a different session. ¿Estoy guardando el pobjeto de forma incorrecta?
user5359531
Parece que el error que estaba obteniendo se resolvió en R 3.3.0 , usando esa versión funciona. Cuando utilicé el gridGraphicsmétodo que se muestra aquí, los colores en el gráfico redibujado se desordenaron, incluso congrid.grab(wrap=TRUE)
user5359531
34

Llegué muy tarde a esto, pero fue la primera pregunta que apareció cuando busqué la pregunta. Así que me gustaría agregar mi solución para futuros espectadores que se encuentren con la pregunta.

Resolví esto usando una función en lugar de un objeto. Por ejemplo, supongamos que queremos comparar dos distribuciones beta con diferentes parámetros. Podemos ejecutar:

z1<-rbeta(10000,5,5)
z2<-rbeta(10000,20,20)
plotit<-function(vector,alpha,beta){
plot(density(vector),xlim=c(0,1))
abline(v=alpha/(alpha+beta),lty="longdash")
}

Y guarde los gráficos como funciones en lugar de objetos.

z.plot1<-function(){plotit(z1,5,5)}
z.plot2<-function(){plotit(z2,20,20)}

A continuación, podemos llamar a cada gráfico como queramos simplemente llamando a los dos gráficos como funciones en lugar de objetos.

z.plot1()

traza la primera parcela y

z.plot2()

traza el segundo.

¡Espero que ayude a alguien que se encuentre con esto más tarde!

rueda de carro
fuente
¡Esto es muy útil! Creo que es una gran idea para preparar gráficos preestablecidos, esto es lo que estaba buscando
Jojostack
¡Este es un enfoque genial de base R! recordPlotes definitivamente útil (si ya tiene una ventana abierta), pero esta respuesta es exactamente lo que la gente busca cuando visita esta publicación. +1!
theforestecologist
Especialmente útil para parcelas múltiples complejas.
Joe
Permítanme unirme al coro de personas que realmente aprecian este truco. También en nombre de mis alumnos :-)
Laryx Decidua
¡El alcance léxico al rescate de nuevo! :)
Jason
17

Puede utilizar la función de enlace activo del pryrpaquete si no desea cambiar directamente los valores del objeto creado.

library(pryr)
a %<a-% plot(1:10,1:10)

Cada vez que escriba aen la consola, el gráfico se volverá a imprimir en la pantalla. El %<a-%operador volverá a ejecutar el script cada vez (en el caso de un gráfico, creo que esto no es un problema). Entonces, esencialmente, cada vez que use ael código se volverá a ejecutar, lo que dará como resultado su gráfico que, por supuesto, puede manipular (superponer otro gráfico en la parte superior) o guardar usando, pngpor ejemplo. Sin aembargo, no se almacenará ningún valor en sí mismo . El valor seguirá siendo NULL.

No sé si lo anterior es lo que está buscando, pero podría ser una solución aceptable.

LyzandeR
fuente
Gracias. Esa es una solución muy útil. ¿Sabes si esto funciona si la parcela se construye a través de varias líneas (como plot(1:10);abline(v=4)por ejemplo)? +1
Remi.b
@ Remi.b Sí, por supuesto que sí. Sin embargo, debe escribirlo así " a %<a-% {plot(1:10);abline(v=4)}. Si lo escribe dentro de esas llaves, puede tener tantas líneas como desee. Además, si desea reasignar un valor a, primero debe eliminarlo con rm(a)y luego reasignarlo con el %<a-%operador, de lo contrario, recibe una advertencia. No sé por qué sucede esto, pero supongo que no es un gran problema.
LyzandeR
¡Esto es realmente genial! Tendré que leer un poco sobre este paquete porque me parece imposible hacer lo que hace esta extraña función %<a-%. Gracias
Remi.b
Sí, es otro de esos paquetes realmente geniales que hizo Hadley. Es un conjunto de funciones que te permite comprender el lenguaje R en profundidad. Échale un vistazo %<d-%también, podría ser útil más adelante. Me alegro de poder ser de ayuda :)
LyzandeR
1
@LyzandeR ¿es posible combinar las parcelas guardadas en una parcela múltiple?
user2300940
-4
library(ggplot2)
# if mygraph is a plot object
ggsave("myplot1.png",mygraph)

# if the plot is in a list (e.g. created by the Bibliometrics package)
ggsave("myplot1.png",mygraphs[[1]])
Dr. T.
fuente
Aunque su respuesta parece 'correcta' (pero no soy un programador de R), es una práctica normal en Stack Overflow agregar un texto explicativo, en lugar de simplemente publicar un bloque de código 'conciso'. Esto hace que la respuesta sea más valiosa a largo plazo y para una gama más amplia de usuarios. (¡Pero tenga un voto a favor, de todos modos!)
Adrian Mole
3
El OP estaba preguntando cómo hacer esto sin usar ggplot2.
Jason