I discovered that if ggplot is the last thing in a function, then calling the function will result in ggplot creating a plot as expected.
But if ggplot is not the last thing in a function -- say it is followed by an assignment (like x <- t) or a return statement (like return(x)) then ggplot will not create a plot.
What is the work around for this?
P.S. please throw in a comment explaining how to create an inline grey background used to indicate code :-)
Use plot for your ggplot object.
func1 <- function() {
require(ggplot2)
ggplot(mtcars, aes(mpg, wt)) + geom_point()
}
func1() # this creates plot
func2 <- function() {
require(ggplot2)
ggplot(mtcars, aes(mpg, wt)) + geom_point()
cat("hey\n")
}
func2() # this does not create plot
func3 <- function() {
require(ggplot2)
plot(ggplot(mtcars, aes(mpg, wt)) + geom_point())
cat("hey\n")
}
func3() # use plot to make sure your plot is displayed
By the way, func1 creates plot not because ggplot is the last thing to do in the function. It creates plot because the function returns the ggplot object and the code func1() invokes the print method of the object.
To see this, If you do a <- func1(), then the plot is not created, but stored in the a variable.
Note: You can use print insted. print and plot are equivalent for the ggplot object.
Related
I thought this was obvious, but recently I was using the package openair and noticed that when I run the following:
library(openair)
myplot <- windRose(mydata)
the plot myplot is still plotted in the viewer. After looking at the windRose function it is obvious the plot function is being called.
However, why does myggplot <- ggplot(mtcars, aes(cyl, mpg)) + geom_point() not have the same outcome of plotting to the viewer. I am guessing the difference is in how these functions are programmed but I cannot easily identify how ggplot handles the plotting part.
This is not a ggplot-specific behavior, but a more general principle: The R REPL doesn't print assignment statements in general, whereas for expressions, it calls print() or show() on the resulting value, depending on the object type (see Autoprinting section of R Internals for details). For example,1
> 1 + 1 # expression
[1] 2
> x <- 1 + 1 # assignment
>
For a ggplot object, calling print on the object triggers a rendering. So, if you don't assign, it gets rendered. For example,
> ggplot(mtcars, aes(hp, mpg)) + geom_point()
> g <- ggplot(mtcars, aes(hp, mpg)) + geom_point()
>
The plot function, on the other hand, includes rendering as part of it, which is why the other function you called gets rendered despite the assignment.
Note that one can use the invisible function to temporarily set R_Visible to FALSE, which turns off the default behavior of printing expressions, but will still push the evaluated result to .Last.value.
> invisible(1 + 1)
> .Last.value
[1] 2
However, because plot() calls a render to the graphics device as part of its code, invisible() will not stop it from rendering.
> invisible(plot(mtcars$hp, mtcars$mpg))
[1] Credit #Gregor
I want to display multiple plots depending on the length of my predictors. I have created two list and then used grid.arrange function to display the plots within these lists, but I am getting the following error message -'only 'grobs' allowed in "gList". Even when I try to use only one list say p, I get the same error message. Please help!
library(ggplot2)
library(gridExtra)
# dependent1 variable
# dependent2 variable
# predictor_vector is a vector of predictors
plot_output(data, dependent1, dependent2, predictor_vector)
{
length<-length(predictor_vector)
p<-list()
g<-list()
for( i in 1:length)
{
p[[i]]<-ggplot(data, aes(y=dependent1, x=predictor_vector[i]))
g[[i]]<-ggplot(data, aes(y=dependent2, x=predictor_vector[i]))
}
do.call("grid.arrange", c(p, g, list(ncol=2)))
}
Posting as an answer only to show the example that's impossible in a comment.
The idiom you're trying to use is correct:
library(ggplot2)
library(gridExtra)
p <- list(ggplot(mtcars, aes(x=wt, y=mpg))+geom_point(col="black"),
ggplot(mtcars, aes(x=wt, y=mpg))+geom_point(col="orange"),
ggplot(mtcars, aes(x=mpg, y=wt))+geom_point(col="blue"))
g <- list(ggplot(mtcars, aes(x=wt, y=mpg))+geom_point(col="red"),
ggplot(mtcars, aes(x=mpg, y=wt))+geom_point(col="green"))
do.call(grid.arrange, c(p, g, list(ncol=2)))
Two variable length ggplot object lists and then the parameter list. You need to provide the data and a more complete loop for us to know how to help you figure out what you're doing incorrectly.
I'm trying to contstuct a function that behaves like a ggplot function, and also returns a ggplot object that other functions may work on further (add facets, apply a theme, etc.).
The hurdle I am facing now is that I cannot get argument passning to the function to work like I would expect it to.
data(iris)
te <- function(data,x,y){
g <- ggplot(data,aes_q(x=quote(x),y=quote(y))) + scale_x_continuous() +
scale_y_continuous() + geom_point()
return(g)
}
te(iris,x=Species,y=Petal.Length)
What I get then is:
Error: geom_point requires the following missing aesthetics: x, y
I hoped that this would enable me to pass the arguments not as strings, but obviously I am doing something wrong here. The odd thing, for me, is that geom_point is the function that is complaining. How come?
Inside a function you need to use substitute instead of quote:
data(iris)
te <- function(data,x,y){
x <- substitute(x)
y <- substitute(y)
g <- ggplot(data,aes_q(x=x,y=y)) + scale_x_discrete() +
scale_y_continuous() + geom_point()
return(g)
}
te(iris,x=Species,y=Petal.Length)
This will work perfect.
P.S. I changed scale_x_continuous to scale_x_discrete because Species is discrete
Try quote when calling the function:
data(iris)
library(ggplot2)
te <- function(data,x,y){
g <- ggplot(data,aes_q(x,y)) + scale_x_continuous() +
scale_y_continuous() + geom_point()
return(g)
}
te(iris,x=quote(Species),y=quote(Petal.Length))
My problem is best understood after reading the R script:
plotHistogram <- function(data, x, binw=0.30, color=FALSE, density=FALSE, h=10, w=10) {
require(ggplot2)
# data$x <- as.numeric(x)
plot <- ggplot(data, aes(x))
if(density & color) {
plot <- plot + geom_density(fill="blue", aes(alpha=0.2))
} else if (density) {
plot <- plot + geom_density()
} else if (color) {
plot <- plot +
geom_histogram(binwidth=binw, aes(y=..density.., fill=..count..)) +
scale_fill_gradient("Count", low="purple", high="red")
} else {
plot <- plot + geom_histogram(binwidth=binw, aes(y=..density.., fill=..count..))
}
ggsave(file="histo_plot.svg", plot=plot, height=h, width=w)
return(plot)
}
Notice the commented line. Normally I have to use this to get ggplot to recognize that x belongs to data. This is a hack. My intent is to plot the name of whatever series is input as x. I'm not sure how to do this because as far as I can tell, I have to store the column to be visualized in some variable, but that variable renames the vector, so there's no good way to find the original name in the data.frame.
I'm sure I'm overlooking a simple solution.
Edit: Concretely expressed problem
Suppose I did the following:
plotHistogram(economics, economics$psavert)
This would result in either an error, or undesired result. If I uncomment that line, a x-axis label "x" is drawn, when what I really want is "psavert".
Suppose I plot something like this:
ggplot(iris, aes(x=Sepal.Length, y=Petal.Length)) + geom_point()
Then I realise that I forgot to store the result (i.e. the ggplot object).
How can I retrieve the ggplot object corresponding to the current device?
Is there some ggplot function I can feed cur.dev() into to retrieve the associated plot object, or is it gone forever?
(Note - in this case I could do p <- .Last.value, but let's assume I've typed a few commands since then so that this is not available.
Motivation - adding a hook to knitr to automagically set fig.cap to the title of the plot (if any)).
You are after last_plot
It retrieves the last plot to be modified or created and is used by ggsave
Note that it is the last plot modified or created
set_last_plot is the relevant code (see the source)
It is important note that creating modifying or rendering a ggplot object will set the last plot.
ggplot(iris, aes(x=Sepal.Length, y=Petal.Length)) + geom_point()
f <- last_plot()
# will return the iris plot
p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
last_plot()
# will return p
f
last_plot()
# is now f
It will also not count any modifications / manipulation using grid or gridExtra (such as grid.arrange / grid.text
The last object assigned (and it does not need to be a plot object) can be recovered with .Last.value
>require(ggplot2)
#Loading required package: ggplot2
ggplot(iris, aes(x=Sepal.Length, y=Petal.Length)) + geom_point()
gp <- .Last.value
gp
This should return plot objects that have been modified by grid functions as long as there was an assignment. I'm not sure it this is true for actions that were mediated through print calls.