Error in trying to write a plotting function in ggplot2 - r

I am trying to write a function in ggplot2 and obtain this error message:
Error in layout_base(data, vars, drop = drop) :
At least one layer must contain all variables used for facetting
Here is my code:
growth.plot<-function(data,x,y,fac){
gp <- ggplot(data = data,aes(x = x, y = y))
gp <- gp + geom_point() + facet_wrap(~ fac)
return(gp)
}
growth.plot(data=mydata, x=x.var, y=y.var,fac= fac.var)
If I try without the function, the plot appears perfectly
gp1 <- ggplot(data = mydata,aes(x = x.var), y = y.var))
gp1+ geom_point()+ facet_wrap(~ fac.var) # this works

Here is reproducible solution where your x, y, and fac arguments must be passed as character:
library(ggplot2)
make_plot = function(data, x, y, fac) {
p = ggplot(data, aes_string(x=x, y=y, colour=fac)) +
geom_point(size=3) +
facet_wrap(as.formula(paste("~", fac)))
return(p)
}
p = make_plot(iris, x="Sepal.Length", y="Petal.Length", fac="Species")
ggsave("iris_plot.png", plot=p, height=4, width=8, dpi=120)
Thanks to commenters #Roland and #aosmith for pointing the way to this solution.

Related

Creating boxplots for visualisation in R using a function

I wrote a code to get boxplots for visualisation in R. The code is running but I am not getting any boxplots. Can you please help identify where I went wrong.
create_boxplots <- function(x, y){
ggplot(data = forest_fires) +
aes_string(x = x, y = y) +
geom_boxplot() +
theme(panel.background = element_rect(fill = "white"))
}
x_var_month <- names(forest_fires)[3]
y_var <- names(forest_fires)[5:12]
month_box <- map2(x_var_month, y_var, create_boxplots)
The code is ok, just that when you call ggplot inside a function, you return the object and it is stored in a list. You need to print it. For example:
library(ggplot2)
library(purrr)
library(gridExtra)
create_boxplots <- function(x, y){
ggplot(data = forest_fires) +
aes_string(x = x, y = y) +
geom_boxplot() +
theme(panel.background = element_rect(fill = "white"))
}
forest_fires = data.frame(matrix(runif(1300),ncol=13))
forest_fires[,3] = factor(sample(1:12,nrow(forest_fires),replace=TRUE))
x_var_month <- names(forest_fires)[3]
y_var <- names(forest_fires)[5:12]
month_box <- map2(x_var_month, y_var, create_boxplots)
This shows you the plot for y_var[1]
month_box[[1]]
#or print(month_box[[1]])
To get everything in 1 plot do:
grid.arrange(grobs=month_box)

Can you have a nested argument in a function in R?

Is it possible to have something like this in R?
plotFunction <- function(gradientCols(x,y)){
p <- ggplot(diamonds, aes(carat, price)) +
scale_fill_gradient(low = x, high = y) +
geom_bin2d()
return(p)
}
plotFunction(gradientCols("red","blue"))
Where the argument gradientCols in the function plotFunction can take 2 additional arguments (i.e., x,y)?
Or is there a better way to do this without having to explicitly state all the individual arguments in the function?
Here, we just pass the 'x' and 'y'
library(ggplot2)
plotFunction <- function(x, y){
ggplot(diamonds, aes(carat, price)) +
scale_fill_gradient(low = x, high = y) +
geom_bin2d()};
plotFunction("red", "blue")

Error with facet_grid() when using a function created for plotting

I have created a function for returning a plot in R. There seems to be a issue with facet_grid() that appears when plotting with the created plot function that does not appear when not using the function (even though I use the exact same lines of code).
# function for plotting
barplot_fill <- function(dataset, x, y, fill, jaar) {
p <- ggplot(dataset, aes(x=x, y=y, fill=fill)) +
geom_bar(stat = "identity") +
facet_grid(~ jaar) +
theme_bw() +
scale_y_continuous(labels=comma)
return(p)
}
I would like to plot variables from the following data frame:
df <- data.frame(V1=c(1,2,3,4), V2=c(20,25,46,13), V3=c('a','a','b','b'), V4=c(2018,2019,2018,2017))
When calling the function, I get the following error:
barplot_fill(df, V1, V2, V3, V4)
Error: At least one layer must contain all faceting variables: dataset$jaar.
* Plot is missing dataset$jaar
* Layer 1 is missing dataset$jaar
When I don't call the created function and just create the plot using the ggplot lines of code, R creates the plot and the error does not appear.
ggplot(df, aes(x=V1, y=V2, fill=V3)) +
geom_bar(stat = "identity") +
theme_bw() +
facet_grid(~ V4) +
scale_y_continuous(labels=comma)
I can't figure out why it gives me an error in the created function and why the error does not appear when run the exact same lines of code when not using the function. Can anyone explain me why the error appears when calling the created function?
The problem is that jaar is not evaluated in the facet_grid call, but ggplot is looking for a jaar column in the data set you provide. Actually, something similar happens in the ggplot-call for x, y, and fill if you remove the fact_grid part of the function:
barplot_fill_no_facet <- function(dataset, x, y, fill, jaar) {
p <- ggplot(dataset, aes(x = x, y = y, fill = fill)) +
geom_bar(stat = "identity") +
theme_bw() +
scale_y_continuous()
return(p)
}
barplot_fill_no_facet(df, V1, V2, V3, V4)
Error in FUN(X[[i]], ...) : object 'V1' not found
One solution uses aes_string and formula for facet_grid:
barplot_fill <- function(dataset, x, y, fill, jaar) {
p <- ggplot(dataset, aes_string(x = x, y = y, fill = fill)) +
geom_bar(stat = "identity") +
facet_grid(formula(paste("~", jaar))) +
theme_bw() +
scale_y_continuous()
return(p)
}
barplot_fill(df, "V1", "V2", "V3", "V4")
Apart from a little glitch with scale_y_continuous (you haven't defined comma), the problem is the evaluation of your variables. For aes, you can use aes_string and pass strings, but facet_grid has a different format. See under Variable Facets here.
barplot_fill <- function(dataset, x, y, fill, jaar) {
jaar <- enquo(jaar)
p <- ggplot(dataset, aes_string(x=x, y=y, fill=fill)) +
geom_bar(stat = "identity") +
facet_grid(cols = vars(!!jaar)) +
theme_bw()
return(p)
}
df <- data.frame(V1=c(1,2,3,4), V2=c(20,25,46,13), V3=c('a','a','b','b'), V4=c(2018,2019,2018,2017))
barplot_fill(df, "V1", "V2", "V3", V4)

return plot and values from a function together [duplicate]

This question already has an answer here:
Custom Function, ggplot and return values
(1 answer)
Closed last year.
I have a function like this:
fun <- function(dataset){
require(ggplot2)
g <- ggplot(dataset, aes(x = x, y = y)) + geom_smooth(method = "lm") + geom_point()
l<-lm(y~x)
return (list(l, g))
}
and I want to return both plot and the values, but it doesn't return the plot and I face this error:
Error in .Call.graphics(C_palette2, .Call(C_palette2, NULL)) :
invalid graphics state
What can I do?
The following works, and you can get the plot. However, R warns that's not the way to do it.
fun <- function(dataset){
require(ggplot2)
p <- ggplot(dataset, aes(x = x, y = y)) +
geom_smooth(method = "lm") + geom_point()
l <- lm(y~x, data=dataset)
return (list(l, p))
}
dataset <- data.frame(x= 1:10, y=1:10)
out <- fun(dataset)
Edit: I've had a look about the warning, it seems like something you can ignore. See link https://stat.ethz.ch/pipermail/r-devel/2016-December/073554.html

R + ggplot: geom_txt label not recognize a variable in function call

I'm an R/ggplot newbie switching over from MatLab.
I would like to create a function using ggplot with linear regression equation printed on the graph (which is discussed in Adding Regression Line Equation and R2 on graph). But here, I am trying to build a function with it but wasn't successful.
I kept getting an error -
"Error in eval(expr, envir, enclos) : object 'label' not found".
One workaround is to define "label" variable outside of the function but I just don't understand why this doesn't work.
Can anyone explain why?
df <- data.frame(x = c(1:100))
df$y <- 2 + 3 * df$x + rnorm(100, sd = 40)
f <- function(DS, x, y, z) {
label <- z
print(label)
ggplot(DS, aes(x=x, y=y)) +
geom_point() +
labs(y=y) +
labs(title=y) +
xlim(0,5)+
ylim(0,5)+
geom_smooth(method="lm", se=FALSE)+
geom_text (aes(x=1, y=4, label=label))
}
f(df, x, y, "aaa") #execution line
See the following code:
library(ggplot2)
df <- data.frame(x = c(1:100))
df$y <- 2 + 3 * df$x + rnorm(100, sd = 40)
f <- function(DS, x, y, z) {
label.df = data.frame(x=1, y=4, label=z)
ggplot(DS, aes_string(x=x, y=y)) +
geom_point() +
labs(y=y) +
labs(title=y) +
geom_smooth(method="lm", se=FALSE)+
geom_text (aes(x=x, y=y, label=label), label.df)
}
f(df, "x", "y", "aaa")
There were a few fixes about your code:
The data you are using in geom_text is the same you have defined in ggplot() unless you change it. Here I have created a temporary data.frame for this purpose called label.df.
The xlim() and ylim() functions were filtering most of your data points, since the range of x and y are much larger than the limits you defined in the original code.
When you want to pass the names of the columns of your data.frame to be used for displaying the graph it would be easier to pass their names as strings (i.e. "x"). This way, the aes() function is also changed to aes_string().
Here is the result:
Edit
Thanks to #Gregor, a simpler version would be:
f <- function(DS, x, y, z) {
ggplot(DS, aes_string(x=x, y=y)) +
geom_point() +
labs(y=y) +
labs(title=y) +
geom_smooth(method="lm", se=FALSE)+
annotate(geom="text", x=1, y=4, label=z)
}

Resources