the question is straight forward. First, I tried an if-else condition within the render plot. Something like
if (input$Next > 0) {
plot(...)
}
else {
We want to show the plotOutput
if the actionButton
was pressed. More specifically, if input.Next > 0
. This condition is evaluated in javaScript
, hence we have a slightly different syntax - instead of $
we use .
after input and we use the parentheses.
conditionalPanel(
condition = "input.Next * 1 > 0",
plotOutput("test")
)
However, it is quite strange that we multiply input.Next
by one. It is necessary because input.Next
, expect a number, returns also attributes. It seems that JavaScript doesn't know how to deal with this...but the multiplication does the trick.
[1] 0
attr(,"class")
[1] "integer" "shinyActionButtonValue"
In this example the plotOutput
appears immediately...definitely too fast.
library(shiny)
ui1 <- shinyUI(fluidPage(
sidebarPanel(
conditionalPanel(
condition = "input.Next * 1 > 0",
plotOutput("test")
),
actionButton("Next", "Next")
)
))
server1 <- shinyServer(function(input, output, session) {
output$test <- renderPlot({
pt <- plot(input$Next, 2)
print(input$Next)
print(pt)
})
})
shinyApp(ui1, server1)
In this example, we're going to "slow down" the speeding plotOutput
. To do so we need the package shinyjs
.
First, we're going to wrap the conditionalPanel
into a div
with an id, say, animation
div(id = "animation",
conditionalPanel(
condition = "input.Next * 1 > 0",
plotOutput("test")
)
)
Then, on the server side, we're going to define the animation in the following way: conditional on the input$next the div should show up with the slide animation.
observe({
toggle(id = "animation", anim = TRUE, animType = "slide",
time = 0.5, condition = input$Next > 0)
})
Full example:
ui2 <- shinyUI(fluidPage(
# we need to include this function in order to use shinyjs functions
useShinyjs(),
sidebarPanel(
actionButton("Next", "Next"),
div(id = "animation",
conditionalPanel(
condition = "input.Next * 1 > 0",
plotOutput("test"),
sliderInput("manipulate", "slider", min = 0, max = 1, value = 1)
)
)
)
))
server2 <- shinyServer(function(input, output, session) {
# Introduce gently the div with an id = "animation" and its all content.
observe({
toggle(id = "animation", anim = TRUE, animType = "slide",
time = 0.5, condition = input$Next > 0)
})
# We could animate only the plotOutput with "toogle(id = test")"
# - it would work as well, but for the first time the plot is shown
# way we would get an errors with margins.
output$test <- renderPlot({
#plot(input$Next, 2)
ggplot(iris, aes(x = Species)) + geom_bar(alpha = input$manipulate)
})
})
shinyApp(ui2, server2)
renderUI
As you pointed out, the another possibility is to use the function renderUI
. If you want to render more than one element at once, you have to wrap them into a list
as in the example below:
library(shiny)
library(ggplot2)
ui3 <- shinyUI(fluidPage(
sidebarPanel(
uiOutput("dynamic"),
actionButton("Next", "Next")
)
))
server3 <- shinyServer(function(input, output, session) {
output$dynamic <- renderUI({
if (input$Next > 0) {
# if we want to render more element, we need the list
list(
plotOutput("test"),
sliderInput("manipulate", "slider", min = 0, max = 1, value = 1)
)
}
})
output$test <- renderPlot({
#plot(input$Next, 2)
ggplot(iris, aes(x = Species)) + geom_bar(alpha = input$manipulate)
})
})
shinyApp(ui3, server3)
Use a conditional panel like so:
library(shiny)
ui =fluidPage(
sidebarPanel(
conditionalPanel(condition="input.Next>0",
plotOutput("test")),
actionButton("Next", "Next")
))
server=shinyServer(function(input, output, session) {
output$test <- renderPlot({
req(input$Next > 0)
pt <- plot(input$Next,2)
print(pt)
})
})
shinyApp(ui=ui,server=server)