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
Force Ggplot Legend to Show All Categories When No Values Are Present
Modifying Ggplot Objects After Creation
How to Append a Whole Dataframe to a CSV in R
Ggplot2: Drop Unused Factors in a Faceted Bar Plot But Not Have Differing Bar Widths Between Facets
How to Combine Ggplot and Dplyr into a Function
Downloading Png from Shiny (R)
R: Extracting "Clean" Utf-8 Text from a Web Page Scraped with Rcurl
How to Facet a Plot_Ly() Chart
Plot Data Over Background Image with Ggplot
Convert Factor to Date/Time in R
R Shiny Table Not Rendering HTML
How to Detect Free Variable Names in R Functions
How to Generalize Outer to N Dimensions
R Sum a Variable by Two Groups