'structure(NULL, *)' deprecated in R 3.5.* when using ggplot2 - r

I'm writing a program which has a step involving ggplot2 in R. The plot's relevant steps are:
ggplot() +
geom_violin(data=x, mapping=aes(x=1, y=Mean_cov)) +
geom_jitter(data=x, mapping=aes(x=3, y=Mean_cov, col=Frac_pos)) +
scale_x_discrete(breaks=c(1,3), labels=c("","")) +
scale_y_continuous(limits=c(0, 50)) +
scale_color_gradient2( breaks=seq(0,100,20),
limits=c(0,100),
low="green3", high="darkorchid4",
midpoint=50, name="% covered") +
coord_flip()
Mean_cov and Frac_pos are colnames() of my data.frame(). 1 and 3 are unelegant solutions I found to obtain a plot that separates the geom_jitter() and the geom_violin() by a sufficient space.
This worked in R/3.3.3 but since our sysadmin updated the default R to R/3.5.2 we are experiencing plotting issues (i.e. the plot gets generated but the axes are overlapping the panel margin, instead of being contained within it). I know I could just point it to R/3.3.3 but I would prefer to make my program compatible with newer R versions, since I want to publish it.
The warning I'm getting is quite popular in R-related error threads:
3: In structure(NULL, class = "waiver") :
Calling 'structure(NULL, *)' is deprecated, as NULL cannot have attributes.
Consider 'structure(list(), *)' instead.
I am aware of other stackoverflow issues similar to mine, like this one:
R c.Date() raises warning Calling 'structure(NULL, *)' is deprecated
However, I couldn't solve the problem following other issues so I decided to open a new one since it seems to be a ggplot2 issue.
Perhaps the error is raised because of a way ggplot2 calls some function in the background?
Here are 10 lines from my data frame:
Frac_pos Mean_cov
99.78591232934406 42.783034429509
99.98996910484291 24.89770493118806
98.9460737536315 19.48427592934241
99.80868782354266 45.07804411433716
99.48891662209545 88.17287692399121
99.89221021636827 30.86539422141599
99.56238183247297 25.512161961209184
99.00406672752926 32.80431986056934
99.22226325737003 29.72798766048967
This is how it should look like (as with R/3.3.3):
This is how it looks like with newer R versions (see that it is broader? Since I have millions of those dots, many of them fall out of the panel):

Related

Disabling only a single ggplot2/tidyverse lifecycle/deprecated warning? (Not all lifecycle warnings)

I have some R code that uses ggplot2 and may continue to use aes_string() for a while despite that function being deprecated. The code also uses source() to bring in some other functions that use aes_string(), which I do not have access to edit without making/maintaining a separate copy of the included code.
I know I can disable all tidyverse lifecycle messages with: rlang::local_options(lifecycle_verbosity = "quiet") but I don't necessarily want to disable all of them - I may still update other parts of the code to match changes in ggplot2, even while continuing to use aes_string().
Is there any way to disable the deprecated message only for aes_string() and not for everything else?
Just wrap the aes_string() call in suppressWarnings():
library(ggplot2)
ggplot(mpg, aes_string("cty", "hwy")) +
geom_point()
# Warning message:
# `aes_string()` was deprecated in ggplot2 3.0.0.
# ℹ Please use tidy evaluation ideoms with `aes()`
ggplot(mpg, suppressWarnings(aes_string("cty", "hwy"))) +
geom_point()
# [no warning printed]
Or if you want to be sure to suppress only that specific warning, you could define a custom handler function like:
suppressDeprecationWarning <- function(...) {
withCallingHandlers(
...,
warning = \(w) if ("`aes_string()` was deprecated in ggplot2 3.0.0." %in% w$message) {
rlang::cnd_muffle(w)
}
)
}
ggplot(mpg, suppressDeprecationWarning(aes_string("cty", "hwy"))) +
geom_point()
# [no warning printed]

Loading an R package without all the names in it

I'm sorry if this a duplicate, but it's un-internet-searchable.
I would like to load ggplot, but without littering my global namespace with all the functions therein.
I am content with accessing the functions as ggplot2::aes(), and I don't want just aes() to work.
In other programming languages, this is the default behaviour.
I think you have really answered this yourself. This works without any library statements as long as ggplot2 is installed:
ggplot2::ggplot(BOD, ggplot2::aes(Time, demand)) + ggplot2::geom_point()
This could alternately be done like this:
ggplot <- ggplot2::ggplot
aes <- ggplot2::aes
geom_point <- ggplot2::geom_point
ggplot(BOD, aes(Time, demand)) + geom_point()
Another possibility is to just temporarily add ggplot2 and then remove it again:
library(ggplot2)
ggplot(BOD, aes(Time, demand)) + geom_point()
detach("package:ggplot2", unload = TRUE)
There are a number of R packages which provide facilities that may be of interest including the modules and import packages on CRAN. Also the klmr modules R package on github (not on CRAN) provides a Python-like framework.

utils::globalVariables(.) not applicable to R CMD CHECK note:no visible binding for global variable '.' [duplicate]

I noticed in checking a package that I obtain notes "no visible binding for global variable" when I use functions like subset that use verbatim names of list elements as arguments.
For example with a data frame:
foo <- data.frame(a=c(TRUE,FALSE,TRUE),b=1:3)
I can do silly things like:
subset(foo,a)
transform(foo,a=b)
Which work as expected. The R code check in R CMD however doesn't understand that these refer to elements and complains about there not being any visible bindings of global variables.
While this works ok, I don't really like having notes in my package and prefer for it to pass the check with no errors, warnings and notes at all. I also don't really want to rework my code too much. Is there a way to write these codes so that it is clear the arguments do not refer to global variables?
To get it past R CMD check you can either :
Use get("b") (but that is onerous)
Place a=b=NULL somewhere higher up in your function (that's what I do)
There was a thread on r-devel a while ago where somebody from r-core basically said (from memory) "NOTES are ok, you know. The assumption is that the author checked it and is ok with the NOTE.". But, I agree with you. I do prefer to have CRAN checks return a clean "OK" on all platforms. That way the user is left in no doubt that it passes checks ok.
EDIT :
Here is the r-devel thread I was remembering (from April 2010). So that appears to suggest that there are some situations where there is no known way to avoid the NOTE, but that's ok.
This is one of the potential "unanticipated consequences" of using subset non-interactively. As it says in the Warning section of ?subset:
This is a convenience function intended for use interactively. For
programming it is better to use the standard subsetting functions like
‘[’, and in particular the non-standard evaluation of argument
‘subset’ can have unanticipated consequences.
From R version 2.15.1 onwards there is a way around this:
if(getRversion() >= "2.15.1") utils::globalVariables(c("a", "othervar"))
As per the warning section of ?subset it is better to use subset interactively, and [ for programming.
I would replace a command like
subset(foo,a)
with
foo[foo$a]
or if foo is a dataframe:
foo[foo$a, ]
you might also like to use with if foo is a dataframe and the expression to be evaluated is complex:
with(foo, foo[a, ])
I had this issue and traced it to my ggplot2 section.
This code provided the error:
ggplot2::ggplot(data = spec.df, ggplot2::aes(E.avg, fraction)) +
ggplot2::geom_line() +
ggplot2::ggtitle(paste0(title))
Adding the data name to the parameters eliminated the not:
ggplot2::ggplot(data = spec.df, ggplot2::aes(spec.df$E.avg, spec.df$fraction)) +
ggplot2::geom_line() +
ggplot2::ggtitle(paste0(title))

Store output from gridExtra::grid.arrange into an object

I am placing multiple plots into one image using gridExtra::grid.arrange and would like to have the option of saving the combined plot as an object that could be returned from within a function as part of a list of returned objects. Ideally, I would like to do this without printing the plot object.
The code below creates two plots, combines them with grid.arrange, and attempts to save the result into x. However, x evaluates to NULL and the plot is printed. The documentation for grid.arrange points me to arrangeGrob and suggests plotting can be turned off using plot=FALSE, but I get an error when I try that because FALSE is not a grob object.
Any suggestions for what I'm not understanding?
# R under development
# Windows 7 (32 bit)
# ggplot2 1.0.0
# gridExtra 0.9.1
p1 <- ggplot(mtcars, aes(x=factor(cyl), y=mpg)) + geom_boxplot()
p2 <- ggplot(mtcars, aes(x=factor(cyl), y=wt)) + geom_boxplot()
x <- gridExtra::grid.arrange(p1, p2)
x
Per the comments, I'm adding this edit. When I try it with arrangeGrob, I get no output at all.
> gridExtra::arrangeGrob(p1, p2)
> print(gridExtra::arrangeGrob(p1, p2))
Error: No layers in plot
> x <- gridExtra::arrangeGrob(p1, p2)
> x
Error: No layers in plot
The code in your edit does not work properly since you didn't load gridExtra.
library(gridExtra)
y <- arrangeGrob(p1, p2, ncol = 1)
class(y)
#[1] "gtable" "grob" "gDesc"
grid.draw(y)
Edit: since version 2.0.0, my comment about grid dependency below is no longer valid, since grid is now imported.
Edit: With gridExtra version >= 2.0.0, there is no need to attach either package,
p <- ggplot2::qplot(1,1)
x <- gridExtra::arrangeGrob(p, p)
grid::grid.draw(x)
Funny that this was asked so recently - I was running into this problem as well this week and was able to solve it in a bit of a hacky way, but I couldn't find any other solution I was happier with.
Problem 1: ggplotGrob is not found
I had to make sure ggplot2 is loaded. I don't completely understand what's happening (I admit I don't fully understand imports/depends/attaching/etc), but the following fixes that. I'd be open to feedback if this is very dangerous.
if (!"package:ggplot2" %in% search()) {
suppressPackageStartupMessages(attachNamespace("ggplot2"))
on.exit(detach("package:ggplot2"))
}
Somebody else linked to this blog post and I think that works as well, but from my (non-complete) understanding, this solution is less horrible. I think.
Problem 2: no layers in plot
As you discovered too, fixing that problem allows us to use grid.arrange, but that returns NULL and doesn't allow saving to an object. So I also wanted to use arrangeGrob but I also ran into the above error when gridExtra was not already loaded. Applying the fix from problem 1 again doesn't seem to work (maybe the package is getting de-attached too early?). BUT I noticed that calling grid::grid.draw on the result of arrangeGrob prints it fine without error. So I added a custom class to the output of arrangeGrob and added a generic print method that simply calls grid.draw
f <- function() {
plot <- gridExtra::arrangeGrob(...)
class(plot) <- c("ggExtraPlot", class(plot))
plot
}
print.ggExtraPlot <- function(x, ...) {
grid::grid.draw(x)
}
Hooray, now I can open a fresh R session with no packages explicitly loaded, and I can successfully call a function that creates a grob and print it later!
You can see the code in action in my package on GitHub.

No visible binding for global variable Note in R CMD check

I noticed in checking a package that I obtain notes "no visible binding for global variable" when I use functions like subset that use verbatim names of list elements as arguments.
For example with a data frame:
foo <- data.frame(a=c(TRUE,FALSE,TRUE),b=1:3)
I can do silly things like:
subset(foo,a)
transform(foo,a=b)
Which work as expected. The R code check in R CMD however doesn't understand that these refer to elements and complains about there not being any visible bindings of global variables.
While this works ok, I don't really like having notes in my package and prefer for it to pass the check with no errors, warnings and notes at all. I also don't really want to rework my code too much. Is there a way to write these codes so that it is clear the arguments do not refer to global variables?
To get it past R CMD check you can either :
Use get("b") (but that is onerous)
Place a=b=NULL somewhere higher up in your function (that's what I do)
There was a thread on r-devel a while ago where somebody from r-core basically said (from memory) "NOTES are ok, you know. The assumption is that the author checked it and is ok with the NOTE.". But, I agree with you. I do prefer to have CRAN checks return a clean "OK" on all platforms. That way the user is left in no doubt that it passes checks ok.
EDIT :
Here is the r-devel thread I was remembering (from April 2010). So that appears to suggest that there are some situations where there is no known way to avoid the NOTE, but that's ok.
This is one of the potential "unanticipated consequences" of using subset non-interactively. As it says in the Warning section of ?subset:
This is a convenience function intended for use interactively. For
programming it is better to use the standard subsetting functions like
‘[’, and in particular the non-standard evaluation of argument
‘subset’ can have unanticipated consequences.
From R version 2.15.1 onwards there is a way around this:
if(getRversion() >= "2.15.1") utils::globalVariables(c("a", "othervar"))
As per the warning section of ?subset it is better to use subset interactively, and [ for programming.
I would replace a command like
subset(foo,a)
with
foo[foo$a]
or if foo is a dataframe:
foo[foo$a, ]
you might also like to use with if foo is a dataframe and the expression to be evaluated is complex:
with(foo, foo[a, ])
I had this issue and traced it to my ggplot2 section.
This code provided the error:
ggplot2::ggplot(data = spec.df, ggplot2::aes(E.avg, fraction)) +
ggplot2::geom_line() +
ggplot2::ggtitle(paste0(title))
Adding the data name to the parameters eliminated the not:
ggplot2::ggplot(data = spec.df, ggplot2::aes(spec.df$E.avg, spec.df$fraction)) +
ggplot2::geom_line() +
ggplot2::ggtitle(paste0(title))

Resources