How to Suppress the Creation of a Plot While Calling a Function in R

How can I suppress the creation of a plot while calling a function in R?

You can wrap the function call like this :

plotMDS.invisible <- function(...){
ff <- tempfile()
png(filename=ff)
res <- plotMDS(...)
dev.off()
unlink(ff)
res
}

An example of call :

x <- matrix(rnorm(1000*6,sd=0.5),1000,6)
rownames(x) <- paste("Gene",1:1000)
x[1:50,4:6] <- x[1:50,4:6] + 2
# without labels, indexes of samples are plotted.
mds <- plotMDS.invisible(x, col=c(rep("black",3), rep("red",3)) )

How to not display a plot drawn by a function and obtain only invisible object?

I'm not sure why you are doing this, presumably you wish to call plot only for some side effect. Usually this would be the case if you are interested in getting a return value from the plot function, for example using boxplot to calculate the statistics.

With some plot methods, there is an argument plot = FALSE you can use. for example with boxplots you can specify boxplot(..., plot = FALSE).

But this does not work with the basic plot function. Other options are to use a different plotting library, such as lattice or ggplot, that allow you to assign a plot to an object, rather than draw it. But if you really need to do this with base plot, then the only way I can think of is to send the output to a device other than your screen. For example, to send the output to a temporary .png file and then delete the file, you can do

some_func <- function() {
png("temp.xyz")
a=plot(1:10, )
dev.off()
file.remove("temp.xyz")
return(invisible(10))
}

my_value <- some_func()

R: Suppress base graphics plot but return plot as object

LocoGris solved the problem in this related question about the behaviour of grid.echo.

The following code will plot the unwanted graphics output into a tempfile, save the plot as a grid object using grid.echo and grid.grab before unlinking the tempfile so that only the plot object remains, thereby producing the besired behaviour:

ff = tempfile()
svg(filename = ff)
plotfun <- function() plot(1:10)
grid.echo(plotfun)
a = grid.grab()
dev.off()
unlink(ff)

The difference to code in question is that the plotting in R base graphics is put into a function and passed to grid.echo, instead of relying on grid.echo to automatically find what it needs from the current device.

Potentially useful note: grid.echo will plot two times, which can be seen if using regular svg() without tempfiles, as two files will appear with the same plot. I assume that the first plot is in R base graphics and the second one is the echo using the grid system.

Call function to generate the value but without plotting the graph

You can provide an argument that allows users to choose whether to plot or not, FALSE by default below. Then just wrap the call to plot() with an if statement that executes if the argument is TRUE.

library(dplyr)
library(tidyverse)
library(lubridate)

Test <- structure(
list(date1= c("2021-06-28","2021-06-28"),
date2 = c("2021-07-01","2021-07-01"),
Category = c("FDE","ABC"),
Week= c("Friday","Monday"),
DR1 = c(14,11),
DR01 = c(14,12), DR02= c(14,12),DR03= c(19,15),
DR04 = c(15,14),DR05 = c(15,14),
DR06 = c(12,14)),
class = "data.frame", row.names = c(NA, -2L))

f1 <- function(df1, dmda, CategoryChosse, plot = FALSE) {

x<-df1 %>% select(starts_with("DR0"))

x<-cbind(df1, setNames(df1$DR1 - x, paste0(names(x), "_PV")))
PV<-select(x, date2,Week, Category, DR1, ends_with("PV"))

med<-PV %>%
group_by(Category,Week) %>%
summarize(across(ends_with("PV"), median),.groups = 'drop')

SPV<-df1%>%
inner_join(med, by = c('Category', 'Week')) %>%
mutate(across(matches("^DR0\\d+$"), ~.x +
get(paste0(cur_column(), '_PV')),
.names = '{col}_{col}_PV')) %>%
select(date1:Category, DR01_DR01_PV:last_col())

SPV<-data.frame(SPV)

mat1 <- df1 %>%
filter(date2 == dmda, Category == CategoryChosse) %>%
select(starts_with("DR0")) %>%
pivot_longer(cols = everything()) %>%
arrange(desc(row_number())) %>%
mutate(cs = cumsum(value)) %>%
filter(cs == 0) %>%
pull(name)

(dropnames <- paste0(mat1,"_",mat1, "_PV"))

datas<-SPV %>%
filter(date2 == ymd(dmda)) %>%
group_by(Category) %>%
summarize(across(starts_with("DR0"), sum),.groups = 'drop') %>%
pivot_longer(cols= -Category, names_pattern = "DR0(.+)", values_to = "val") %>%
mutate(name = readr::parse_number(name))
colnames(datas)[-1]<-c("Days","Numbers")

if(as.Date(dmda) < min(as.Date(df1$date1))){
datas <- datas %>%
group_by(Category) %>%
slice(1:max(Days)+1) %>%
ungroup
}else{
datas <- datas %>%
group_by(Category) %>%
slice((as.Date(dmda) - min(as.Date(df1$date1) [
df1$Category == first(Category)])):max(Days)+1) %>%
ungroup
}

model <- nls(Numbers ~ b1*Days^2+b2,start = list(b1 = 0,b2 = 0),data = datas, algorithm = "port")
coef_val<-coef(model)[2]

if(plot){
new.data <- data.frame(Days = with(datas, seq(min(Days),max(Days),len = 45)))
new.data <- rbind(0, new.data)

plot(Numbers ~ Days, xlim= c(0,45), ylim= c(0,30),
xaxs='i',data = datas,main = paste0(dmda, "-", CategoryChosse))
lines(new.data$Days,predict(model,newdata = new.data),lwd=2)
points(0, coef_val, col="red",pch=19,cex = 2,xpd=TRUE)
}

return(coef_val)
}

Demonstrating it in use:


f1(Test, "2021-07-01", "ABC")
f1(Test, "2021-07-01", "ABC", plot = TRUE)

Suppress output of a function

It isn't clear why you want to do this without sink, but you can wrap any commands in the invisible() function and it will suppress the output. For instance:

1:10 # prints output
invisible(1:10) # hides it

Otherwise, you can always combine things into one line with a semicolon and parentheses:

{ sink("/dev/null"); ....; sink(); }

R - Generate a plot without displaying it

edit:

simply adding plot = FALSE won't work here because you want to get some parameters that are produced while plotting. In this case, you can follow somthing similar to this question.

histylim <- function(...){
ff <- tempfile()
png(filename=ff)
res <- hist(...)
corners <- par("usr")
dev.off()
unlink(ff)
return(c(corners[3], corners[4]))
}

histylim(mtcars$mpg)
#> [1] -0.48 12.48
histylim(mtcars$disp)
#> [1] -0.28 7.28

the following won't work for you

Add the argument plot=FALSE to the histogram function and if/when needed, plot the object by calling it within plot(), as in:

mtcars

p1 <- hist(mtcars$mpg, plot = FALSE)
plot(p1)

ggplot2: suppress drawing of plot when calling print method

If you look inside ggplot2:::print.ggplot you'll discover that what you probably want to use is either ggplot_build() or ggplot_gtable(), depending on what information you want to inspect.

ggplot_build returns the data object that is invisibly returned by ggplot2's print method, so that's probably what you're after. ggplot_gtable returns the grobs themselves, which allows for direct modification of the grid graphics objects themselves.

last line of an R function prevent the plotting

The underlying cause for the unexpected behavior is that emmeans uses ggplot2 as plotting method. You may examine the code of function emmeans:::.plot.srg. This is why you can store the plot in an object (p) and print it:

foo1 <- function(fit, plot=TRUE) {
vc <- VarCorr(fit)
f <- as.formula(bquote(pairwise ~ .(terms(fit)[[3]])))
ems <- emmeans(fit, f, infer=c(TRUE, TRUE))
sigma <- sqrt(sum(as.numeric(c(attr(vc[[1]], "stddev"), attr(vc, "sc")))^2))
p <- plot(ems)
if(plot) print(p)
return(sigma)
}

foo1(m, plot=TRUE) ## plots
# [1] 126.6106

Intuitively we expect the behavior like in your foo3 <- function(x = 1:3){; plot(x); return(x); }; foo3() example:

foo2 <- function(x, plot=TRUE) {
y <- seq_len(x)^2
if(plot) plot(seq_len(x), y)
return(y)
}
foo2(20) ## plots
# [1] 1 4 9 16 25 36 49 64 81 100 121 144 169
# [14] 196 225 256 289 324 361 400

But this works differently, when one uses ggplot. When we don't store the "ggplot" object, a following line will "overwrite" the plot.

library(ggplot2)
foo3a <- function(x, plot=TRUE) {
y <- seq_len(x)^2
if(plot) ggplot(mapping=aes(seq_len(x), y)) + geom_point()
return(y) ## try to comment/un-comment this line
}
foo3a(20) ## won't plot, just output of y (depending on `return`)

Therefore we have to actually print the "ggplot" object (I show this by storing the plot in p in function foo3b), if it's not the last line of the function.

foo3b <- function(x, plot=TRUE) {
y <- seq_len(x)^2
p <- ggplot(mapping=aes(seq_len(x), y)) + geom_point()
if(plot) print(p)
return(y) ## try to comment/un-comment this line (works in both cases)
}
foo3b(20) ## plots
# [1] 1 4 9 16 25 36 49 64 81 100 121 144 169
# [14] 196 225 256 289 324 361 400

Note that the use of return also is useful.

Suppress output, keep pander and plot in R markdown

Using the following works:

rf_select <- var.select.rfsrc(rf_all, verbose=FALSE)
cat("\n")
pander(rf_select$varselect)

The problem is that var.select.rfsrc() uses cat() instead of message(), and somehow adding a newline is necessary since otherwise the first pander table is run together with the previous line in the markdown file.



Related Topics



Leave a reply



Submit