Pass function argument to ggplot label [duplicate] - r

I need to wrap ggplot2 into another function, and want to be able to parse variables in the same manner that they are accepted, can someone steer me in the correct direction.
Lets say for example, we consider the below MWE.
#Load Required libraries.
library(ggplot2)
##My Wrapper Function.
mywrapper <- function(data,xcol,ycol,colorVar){
writeLines("This is my wrapper")
plot <- ggplot(data=data,aes(x=xcol,y=ycol,color=colorVar)) + geom_point()
print(plot)
return(plot)
}
Dummy Data:
##Demo Data
myData <- data.frame(x=0,y=0,c="Color Series")
Existing Usage which executes without hassle:
##Example of Original Function Usage, which executes as expected
plot <- ggplot(data=myData,aes(x=x,y=y,color=c)) + geom_point()
print(plot)
Objective usage syntax:
##Example of Intended Usage, which Throws Error ----- "object 'xcol' not found"
mywrapper(data=myData,xcol=x,ycol=y,colorVar=c)
The above gives an example of the 'original' usage by the ggplot2 package, and, how I would like to wrap it up in another function. The wrapper however, throws an error.
I am sure this applies to many other applications, and it has probably been answered a thousand times, however, I am not sure what this subject is 'called' within R.

The problem here is that ggplot looks for a column named xcol in the data object. I would recommend to switch to using aes_string and passing the column names you want to map using a string, e.g.:
mywrapper(data = myData, xcol = "x", ycol = "y", colorVar = "c")
And modify your wrapper accordingly:
mywrapper <- function(data, xcol, ycol, colorVar) {
writeLines("This is my wrapper")
plot <- ggplot(data = data, aes_string(x = xcol, y = ycol, color = colorVar)) + geom_point()
print(plot)
return(plot)
}
Some remarks:
Personal preference, I use a lot of spaces around e.g. x = 1, for me this greatly improves the readability. Without spaces the code looks like a big block.
If you return the plot to outside the function, I would not print it inside the function, but just outside the function.

This is just an addition to the original answer, and I do know that this is quite an old post, but just as an addition:
The original answer provides the following code to execute the wrapper:
mywrapper(data = "myData", xcol = "x", ycol = "y", colorVar = "c")
Here, data is provided as a character string. To my knowledge this will not execute correctly. Only the variables within the aes_string are provided as character strings, while the data object is passed to the wrapper as an object.

Related

How to make my custom `$<-` method honor `invisible()`

I am documenting my research in rmarkdown workbooks but want to also save my ggplots into a variable to reconfigure the plots for other cases, for example resize them for presentations.
First, I had a function that prints my plot and saves into a global variable:
PLOTS <- list()
`%<p%` <- function(name, ggplot){
PLOTS[[name]] <<- ggplot
print(ggplot)
return(invisible(NULL)) # better use ggplot here (if used with %>but this is easier for question
}
# Plots and saves
"testplot" %<p% qplot(x = Sepal.Length, y = Sepal.Width, data = iris)
Soon I had the problem that I want to save one version of the plot, but plot another version, for example save the plot but then plot in my workbook two versions with different x axis limits. So I introduced that the function recognizes invisible():
`%<p%`<- function(name, ggplot){
v <- withVisible(ggplot)$visible
if(v) print(ggplot)
PLOTS[[name]] <<- ggplot
return(invisible(NULL))
}
# Save full plot but print only x between 4 and 5
"testplot" %<p% invisible(qplot(x = Sepal.Length, y = Sepal.Width, data = iris))
PLOTS$testplot + coord_cartesian(xlim = c(4,5))
Works beautifully. Then I got really lazy and wanted to use the RStudio shortcut for <- instead of typing unwieldy special characters for %<p%, so I thought of making this function an implementation of the $<- generic, for a new class "plotlist". I then create a list with this new class to cause invokation of `$<-.plotlist`() when an element is assigned to this.
PLOTS2 <- structure(list(), class = "plotlist")
`$<-.plotlist` <- function(x, name, value){
v <- withVisible(value)$visible
if(v) print(value)
NextMethod()
}
But now things get strange as now the invisible() does not work anymore. For example, this renders the ggplot:
PLOTS2$test <- invisible(qplot(x = Sepal.Length, y = Sepal.Width, data = iris))
On the other hand, if I hadn't used the custom $<- implementation, it wouldn't even print by default, for example if I use my ordinary list without the special class "plotlist" to store my plot!
PLOTS$test <- qplot(x = Sepal.Length, y = Sepal.Width, data = iris)
How is this? I do not really know how invisible() works and the manuals of invisible() and withVisibility() say only the object stays invisible "for a while". What are the criteria how long is an object invisible, why is it not in my custom $<- implementation and can I make it honor invisible()?

Write function to plot data, requires passing data.frame column names

I would like to write a function to create plots (in order to create multiple plots without listing the design settings every time). The pirateplot function that I use requires columnnames and a dataframe as input, which causes problems.
My not-working code is:
pirateplot_default <- function(DV,IV,Dataset) {
plot <- pirateplot(formula = DV ~ IV,
data = Dataset,
xlab = "Solution")
return(plot)
}
I have tried "as.name" (saw that here) but it did not work.
using data[DV] is no option because the pirateplot function requires a different notation
I know that there are similar questions here,here,here, and this probably qualifies as duplicate for more skilled programmers, but I did not manage to apply the solutions at other questions to my problem, so hoping for help.
Here is an example
pirateplot_default <- function(DV,IV,Dataset) {
tmp=as.formula(paste0(DV,"~",paste0(IV,collapse="+")))
plot <- pirateplot(formula = tmp,
data = Dataset,
xlab = "Solution")
return(plot)
}
pirateplot_default("mpg",c("disp","cyl","hp"),mtcars)

R function: removing objects from workspace

In my function, I need to store some objects in the workspace using e.g.
matrix <<- mean(matrix)
as I am referring to that object in other functions nested within the "global function". However, I would like to delete these objects at the end of the "global function". How can this be achieved? rm() does not work...
UPDATE:
I outsourced the plotting part of my function and am sourcing this within the "higher order function".
The plotting function sort of looks like this
plot_minaverage <- function(minaverage){
for_minaverage_plot.time <- rep(seq(1,1440),2)
seq <- seq(start.time*60, length.out = 1440)
minaverage_plot_time <- for_minaverage_plot.time[seq]
minaverage_plot_df <- data.frame (minaverage_plot_time, minaverage)
pp <- ggplot(minaverage_plot_df, aes(x=minaverage_plot_time, y = minaverage))+
geom_bar(stat="identity", width = 1, position = position_dodge(width = 0.5))+
theme_bw()+
print(pp)
}
The problem I have is that minverage is computed in the "higher order" function and when I do not store it in workspace as mentioned above, the plotting function cannot access it.
Thanks so much for your thoughts on this!

Cannot save plots as pdf when ggplot function is called inside a function

I am going to plot a boxplot from a 4-column matrix pl1 using ggplot with dots on each box. The instruction for plotting is like this:
p1 <- ggplot(pl1, aes(x=factor(Edge_n), y=get(make.names(y_label)), ymax=max(get(make.names(y_label)))*1.05))+
geom_boxplot(aes(fill=method), outlier.shape= NA)+
theme(text = element_text(size=20), aspect.ratio=1)+
xlab("Number of edges")+
ylab(y_label)+
scale_fill_manual(values=color_box)+
geom_point(aes(x=factor(Edge_n), y=get(make.names(true_des)), ymax=max(get(make.names(true_des)))*1.05, color=method),
position = position_dodge(width=0.75))+
scale_color_manual(values=color_pnt)
Then, I use print(p1) to print it on an opened pdf. However, this does not work for me and I get the below error:
Error in make.names(true_des) : object 'true_des' not found
Does anyone can help?
Your example is not very clear because you give a call but you don't show the values of your variables so it's really hard to figure out what you're trying to do (for instance, is method the name of a column in the data frame pl1, or is it a variable (and if it's a variable, what is its type? string? name?)).
Nonetheless, here's an example that should help set you on the way to doing what you want:
Try something like this:
pl1 <- data.frame(Edge_n = sample(5, 20, TRUE), foo = rnorm(20), bar = rnorm(20))
y_label <- 'foo'
ax <- do.call(aes, list(
x=quote(factor(Edge_n)),
y=as.name(y_label),
ymax = substitute(max(y)*1.05, list(y=as.name(y_label)))))
p1 <- ggplot(pl1) + geom_boxplot(ax)
print(p1)
This should get you started to figuring out the rest of what you're trying to do.
Alternately (a different interpretation of your question) is that you may be running into a problem with the environment in which aes evaluates its arguments. See https://github.com/hadley/ggplot2/issues/743 for details. If this is the issue, then the answer might to override the default value of the environment argument to aes, for instance: aes(x=factor(Edge_n), y=get(make.names(y_label)), ymax=max(get(make.names(y_label)))*1.05, environment=environment())

How to draw loess estimation in GGally using ggpairs?

I tried GGally package a little bit. Especially the ggpairs function. However, I cannot figure out how to use loess instead of lm when plot smooth. Any ideas?
Here is my code:
require(GGally)
diamonds.samp <- diamonds[sample(1:dim(diamonds)[1],200),]
ggpairs(diamonds.samp[,c(1,5)],
lower = list(continuous = "smooth"),
params = c(method = "loess"),
axisLabels = "show")
Thanks!
P.S. compare with the plotmatrix function, ggpairs is much much slower... As a result, most of the time, I just use plotmatrix from ggplot2.
Often it is best to write your own function for it to use. Adapted from this answer to similar question.
library(GGally)
diamonds_sample = diamonds[sample(1:dim(diamonds)[1],200),]
# Function to return points and geom_smooth
# allow for the method to be changed
custom_function = function(data, mapping, method = "loess", ...){
p = ggplot(data = data, mapping = mapping) +
geom_point() +
geom_smooth(method=method, ...)
p
}
# test it
ggpairs(diamonds_sample,
lower = list(continuous = custom_function)
)
Produces this:
Well the documentation doesn't say, so use the source, Luke
You can dig deeper into the source with:
ls('package:GGally')
GGally::ggpairs
... and browse every function it references ...
seems like the args get mapped into ggpairsPlots and then -> plotMatrix which then gets called
So apparently selecting smoother is not explicitly supported, you can only select continuous = "smooth". If it behaves like ggplot2:geom_smooth it internally automatically figures out which of the supported smoothers to call (loess for <1000 datapoints, gam for >=1000).
You might like to step it through the debugger to see what's happening inside your plot. I tried to follow the source but my eyes glaze over.
or 2. Browse on https://github.com/ggobi/ggally/blob/master/R/ggpairs.r [4/14/2013]
#' upper and lower are lists that may contain the variables 'continuous',
#' 'combo' and 'discrete'. Each element of the list is a string implementing
#' the following options: continuous = exactly one of ('points', 'smooth',
#' 'density', 'cor', 'blank') , ...
#'
#' diag is a list that may only contain the variables 'continuous' and 'discrete'.
#' Each element of the diag list is a string implmenting the following options:
#' continuous = exactly one of ('density', 'bar', 'blank');

Resources