Reputation: 4716
I would like to run R code in two locations, in an Rnw file and as an interactive shiny R markdown document.
Thus, what I need, since interactive shiny components do not work in Rnw files, is a code snippet in R that detects whether to load the interactive code or not.
This seems to work, but it feels like a quick hack:
if (exists("input")) { # input is provided by shiny
# interactive components like renderPlot for shiny
} else {
# non-interactive code for Rnw file
}
Is there a stable solution or something like a global variable that I can access that says whether shiny is running at the moment? Or should I check whether the shiny
package is loaded?
What's safest?
Upvotes: 7
Views: 1417
Reputation: 545588
This information is provided directly via Shiny’s isRunning
function.
Outdated answer below:
You can do the following:
shiny_running = function () {
# Look for `runApp` call somewhere in the call stack.
frames = sys.frames()
calls = lapply(sys.calls(), `[[`, 1)
call_name = function (call)
if (is.function(call)) '<closure>' else deparse(call)
call_names = vapply(calls, call_name, character(1))
target_call = grep('^runApp$', call_names)
if (length(target_call) == 0)
return(FALSE)
# Found a function called `runApp`, verify that it’s Shiny’s.
target_frame = frames[[target_call]]
namespace_frame = parent.env(target_frame)
isNamespace(namespace_frame) && environmentName(namespace_frame) == 'shiny'
}
Now you can simply use shiny_running()
in code and get a logical value back that indicates whether the document is run as a Shiny app.
This is probably (close to) the best way, according to a discussion on Shiny the mailing list — but do note the caveats mentioned in the discussion.
Adapted from code in the “modules” package.
Alternatively, the following works. It may be better suited for the Shiny/RMarkdown use-case, but requires the existence of the YAML front matter: It works by reading the runtime
value from that.
shiny_running = function ()
identical(rmarkdown::metadata$runtime, 'shiny')
Upvotes: 3
Reputation: 3311
Update: After Konrad Rudolphs comment I rethought my approach. My original answer can be found down below.
My approach is different from Konrad Rudolphs and maybe different to the OPs initial thoughts. The code speaks for itself:
if (identical(rmarkdown::metadata$runtime, "shiny")) {
"shinyApp"
} else {
"static part"
}
I would not run this code from inside an app but use it as a wrapper around the app. If the code resides within a .Rmd
with runtime: shiny
in the YAML front matter it will start the app, if not, it will show the static part.
I guess that should do what you wanted, and be as stable as it could get.
My original thought would have been to hard code whether or not you were in an interactive document:
document_is_interactive <- TRUE
if (document_is_interactive) {
# interactive components like renderPlot for shiny
} else {
# non-interactive code for Rnw file
}
Although possible, this could lead to problems and would therefore be less stable than other the approach with rmarkdown::metadata$runtime
.
Upvotes: 2