I have two input selection and an action button to generate a plot and download the data. I would like to clear the output contents (plot and download button) any time there is a change in the input selection. The code below will only clear the plot and not the download button. Not sure if the reactiveValuesunder the downloadhandleris correct.
library(shiny)
library(ggplot2)
library(openxlsx)
ui = fluidPage(
textInput("textT", label = "Title", value = ""),
textInput("textX", label = "X-Axis Label", value = ""),
actionButton("Btn", "Run", icon=icon("play-circle")),
plotOutput('plot1'),
conditionalPanel(condition = "input.Btn>0", downloadButton("dwload", "Download"))
)
server = function(input, output, session) {
v <- reactiveValues(clearAll = TRUE)
observeEvent(c(input$textT, input$textX), {
v$clearAll <- TRUE
}, priority = 10)
observeEvent(input$Btn, {
output$plot1 = renderPlot({
if (v$clearAll)
return()
else
ggplot(mtcars, aes(x= gear, y= carb)) + geom_line() +ggtitle(input$textT) + xlab(input$textX)
})
output$dwload <- downloadHandler(
filename = function() {
paste0("Checks-", gsub(" ", "_", gsub(":", ".", Sys.time())), ".xlsx")
},
content = function(file) {
if (v$clearAll)
return()
else
quick_xlsx(mtcars, file=file)
}
)
v$clearAll <- FALSE
}, priority = 10)
}
shinyApp(ui, server)
I'd appreciate any help.
Thank you!
Here is a solution using renderUI and req:
library(shiny)
library(ggplot2)
library(openxlsx)
ui <- fluidPage(
textInput("textT", label = "Title", value = ""),
textInput("textX", label = "X-Axis Label", value = ""),
actionButton("Btn", "Run", icon=icon("play-circle")),
uiOutput("widgets")
)
server <- function(input, output, session) {
hideAll <- reactiveVal(TRUE)
observeEvent(list(input$textT, input$textX), {
hideAll(TRUE)
})
observeEvent(input$Btn, {
req(input$textT)
req(input$textX)
hideAll(FALSE)
})
output$plot1 <- renderPlot({
ggplot(mtcars, aes(x= gear, y= carb)) + geom_line() +
ggtitle(input$textT) + xlab(input$textX)
})
output$dwload <- downloadHandler(
filename = function() {
paste0("Checks-", gsub(" ", "_", gsub(":", ".", Sys.time())), ".xlsx")
},
content = function(file) {
quick_xlsx(mtcars, file=file)
}
)
output$widgets <- renderUI({
req(!hideAll())
tagList(
plotOutput('plot1'),
downloadButton("dwload", "Download")
)
})
}
shinyApp(ui, server)
Related
The below reproducible code allows the user to select either a data table or a plot of the data for viewing (via input$view). I'm trying to create a conditional around the downloadHandler() so that if the user is viewing the data table and chooses to download, then the data is downloaded; otherwise if the user is viewing the plot and chooses to download then a plot in PNG format is downloaded. I'm running into issues around input$view reactivity. How would I modify the code below to conditionally download whichever (data or plot) the user is viewing?
The code as posted below works for viewing either data or plot, but only allows the data table to be downloaded. Offending lines of code that otherwise cause a crash are commented out.
Reproducible code:
library(shiny)
library(ggplot2)
ui <- fluidPage(
radioButtons("view",
label = "View data or plot",
choiceNames = c('Data','Plot'),
choiceValues = c('viewData','viewPlot'),
selected = 'viewData',
inline = TRUE
),
conditionalPanel("input.view == 'viewData'",tableOutput("DF")),
conditionalPanel("input.view == 'viewPlot'",plotOutput("plotDF")),
downloadButton("download","Download",style = "width:20%;")
)
server <- function(input, output, session) {
data <- data.frame(Period = c(1,2,3,4,5,6),Value = c(10,20,15,40,35,30))
data1 <- reactiveValues()
inputView <- reactive(input$view) # attempt to make input$view reactive
observeEvent(input$view,{data1$plot <- ggplot(data, aes(Period,Value)) + geom_line()})
output$DF <- renderTable(data)
output$plotDF <- renderPlot(data1$plot)
output$download <-
# if(inputView() == 'viewData'){
downloadHandler(
filename = function()
paste("dataDownload","csv",sep="."),
content = function(file){
write.table(
data,
na = "",
file,
sep = ",",
col.names = TRUE,
row.names = FALSE)
}
)
# }
# else{
# downloadHandler(
# filename = function(){paste("plotDownload",'.png',sep='')},
# content = function(file){
# ggsave(file,plot=data1$plot)
# }
# )
# }
}
shinyApp(ui, server)
Try this
library(shiny)
library(ggplot2)
ui <- fluidPage(
radioButtons("view",
label = "View data or plot",
choiceNames = c('Data','Plot'),
choiceValues = c('viewData','viewPlot'),
selected = 'viewData',
inline = TRUE
),
conditionalPanel("input.view == 'viewData'",tableOutput("DF")),
conditionalPanel("input.view == 'viewPlot'",plotOutput("plotDF")),
#downloadButton("download","Download",style = "width:20%;")
uiOutput("plotrtable")
)
server <- function(input, output, session) {
data <- data.frame(Period = c(1,2,3,4,5,6),Value = c(10,20,15,40,35,30))
data1 <- reactiveValues()
inputView <- reactive(input$view) # attempt to make input$view reactive
observeEvent(input$view,{data1$plot <- ggplot(data, aes(Period,Value)) + geom_line()})
output$DF <- renderTable(data)
output$plotDF <- renderPlot(data1$plot)
output$plotrtable <- renderUI({
if(input$view == 'viewData'){downloadButton("download","Download",style = "width:20%;") }
else {downloadButton("downloadp","Download",style = "width:20%;") }
})
output$download <- downloadHandler(
filename = function()
paste("dataDownload","csv",sep="."),
content = function(file){
write.table(
data,
na = "",
file,
sep = ",",
col.names = TRUE,
row.names = FALSE)
}
)
output$downloadp <- downloadHandler(
filename = function(){paste("plotDownload",'.png',sep='')},
content = function(file){
ggsave(file,plot=data1$plot)
}
)
}
shinyApp(ui, server)
I'm working on a shiny dashboard that makes heavy use of shiny modules and my client has asked me to make it so that the same two inputs from my dashboard's various tabs take on the same values regardless of tab. I'm having a huge problem doing this and was able to recreate it using a toy example that you'll find below.
#app.R
library(data.table)
library(shiny)
library(ggplot2)
library(ggthemes)
library(shinythemes)
source("Modules.R")
penguins <<- as.data.table(palmerpenguins::penguins)
ui = uiOutput("ui")
inputs <<- reactiveValues(species = NULL, island = NULL)
server <- function(input, output, session) {
bill_species_server("tab1")
flipper_mass_scatter_server("tab2")
output$ui = renderUI({
fluidPage(
titlePanel("", "Penguin Dashboard"),
tabsetPanel(
tabPanel("Bill Length by Species",
ui_code("tab1")
),
tabPanel("Flipper Length by Body Mass",
ui_code("tab2")
)
)
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
#Modules.R
ui_code = function (id) {
ns = NS(id)
sidebarLayout(position = "left",
sidebarPanel(
selectInput(ns("species"), "Choose 1+ species:", choices = penguins[, sort(unique(species))], multiple = TRUE),
selectInput(ns("island"), "Choose 1+ islands:", choices = penguins[, sort(unique(island))], multiple = TRUE)
),
mainPanel(
plotOutput(ns("plot"))
)
)
}
bill_species_server = function(id) {
moduleServer(id, function(input, output, session) {
observeEvent(inputs$species, ignoreInit = TRUE, ignoreNULL = TRUE, {
if (length(inputs$species) > 0) {
updateSelectInput(session = session, inputId = "species", selected = inputs$species)
}
})
observeEvent(inputs$island, ignoreInit = TRUE, ignoreNULL = TRUE, {
if (length(inputs$island) > 0) {
updateSelectInput(session = session, inputId = "island", selected = inputs$island)
}
})
output$plot = renderPlot({
if (length(input$species) > 0) {
penguins = penguins[species %in% input$species]
}
if (length(input$island) > 0) {
penguins = penguins[island %in% input$island]
}
ggplot(penguins) + geom_histogram(aes(x = `bill_length_mm`, fill = species)) + scale_fill_canva(palette = "Striking and energetic")
})
observeEvent(input$species, ignoreNULL = TRUE, ignoreInit = TRUE, {
inputs$species = input$species
})
observeEvent(input$island, ignoreNULL = TRUE, ignoreInit = TRUE, {
inputs$island = input$island
})
})
return(inputs)
}
flipper_mass_scatter_server = function (id) {
moduleServer(id, function(input, output, session) {
observeEvent(inputs$species, ignoreInit = TRUE, ignoreNULL = TRUE, {
if (length(inputs$species) > 0) {
updateSelectInput(session = session, inputId = "species", selected = inputs$species)
}
})
observeEvent(inputs$island, ignoreInit = TRUE, ignoreNULL = TRUE, {
if (length(inputs$island) > 0) {
updateSelectInput(session = session, inputId = "island", selected = inputs$island)
}
})
output$plot = renderPlot({
if (length(input$species) > 0) {
penguins = penguins[species %in% input$species]
}
if (length(input$island) > 0) {
penguins = penguins[island %in% input$island]
}
ggplot(penguins) + geom_point(aes(x = `flipper_length_mm`, y = body_mass_g, colour = species)) + scale_colour_canva(palette = "Striking and energetic")
})
observeEvent(input$species, ignoreNULL = TRUE, ignoreInit = TRUE, {
inputs$species = input$species
})
observeEvent(input$island, ignoreNULL = TRUE, ignoreInit = TRUE, {
inputs$island = input$island
})
})
return(inputs)
}
So the two inputs that I'm trying to link in this toy example are species and island. I've set it up so that when someone makes a new selection on either input, an observer should update a global variable which in this case I've labelled inputs. And then if inputs is updated, the other tab should then update its own selectInput.
Weirdly, I find that with this code, if I make my selections kind of slowly, all works just fine! However, the moment that I click 2+ choices in rapid succession, it causes an infinite loop to happen in the current tab where the second choice appears, then disappears, then appears... etc. Conversely, when I have 3 choices selected and try to delete options in rapid succession, it just doesn't let me delete all choices!!
So weird.
Anyone know what the problem is with my code, and how I can force the inputs in both tabs to keep the same values as chosen in the other tabs?
Thanks!
I significantly restructured how I approached this problem and came up with a solution. Basically, I used shinydashboard and decided that I would define the species and island selectInput controls outside of my modules.
The values to those controls were then passed to the modules as reactive objects that were then used to filter the data before the data got plotted. This works so much better now! Have a look at my two files:
#app.R
library(data.table)
library(shiny)
library(ggplot2)
library(ggthemes)
library(shinythemes)
library(shinydashboard)
source("Modules.R")
penguins <<- as.data.table(palmerpenguins::penguins)
ui = dashboardPage(header = dashboardHeader(title = "Penguin Dashboard"),
sidebar = dashboardSidebar(
sidebarMenu(id = "tabs",
selectInput("species", "Choose 1+ species:", choices = penguins[, sort(unique(species))], multiple = TRUE),
selectInput("island", "Choose 1+ islands:", choices = penguins[, sort(unique(island))], multiple = TRUE),
menuItem("Bill Length by Species", expandedName = "tab1", tabName = "tab1", startExpanded = TRUE,
sliderInput("mass", "Select a range of body masses:",
min = penguins[, min(body_mass_g, na.rm=TRUE)],
max = penguins[, max(body_mass_g, na.rm=TRUE)],
value = penguins[, range(body_mass_g, na.rm=TRUE)])
),
menuItem("Flipper Length by Body Mass", expandedName = "tab2", tabName = "tab2",
checkboxGroupInput("sex", "Choose sex of penguins:",
choices = c("male","female")))
)),
body = dashboardBody(
uiOutput("plots")
)
)
#inputs <<- reactiveValues(species = NULL, island = NULL)
server <- function(input, output, session) {
#inputs <- reactiveValues(species=input$species, island=input$island)
in_species = reactive({input$species})
in_island = reactive({input$island})
in_mass = reactive({input$mass})
in_sex = reactive({input$sex})
bill_species_server("tab1", in_species, in_island, in_mass)
flipper_mass_scatter_server("tab2", in_species, in_island, in_sex)
output$plots = renderUI({
validate(need(!is.null(input$sidebarItemExpanded), ""))
if (input$sidebarItemExpanded == "tab1") {
ui_code("tab1")
} else {
ui_code("tab2")
}
})
}
# Run the application
shinyApp(ui = ui, server = server)
#Modules.R
ui_code = function (id) {
ns = NS(id)
plotOutput(ns("plot"))
}
bill_species_server = function(id, in_species, in_island, in_mass) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
output$plot = renderPlot({
if (length(in_species()) > 0) {
penguins = penguins[species %in% in_species()]
}
if (length(in_island()) > 0) {
penguins = penguins[island %in% in_island()]
}
penguins = penguins[body_mass_g %between% c(in_mass()[1], in_mass()[2])]
ggplot(penguins) + geom_histogram(aes(x = `bill_length_mm`, fill = species)) + scale_fill_canva(palette = "Striking and energetic")
})
})
}
flipper_mass_scatter_server = function (id, in_species, in_island, in_sex) {
moduleServer(id, function(input, output, session) {
output$plot = renderPlot({
if (length(in_species()) > 0) {
penguins = penguins[species %in% in_species()]
}
if (length(in_island()) > 0) {
penguins = penguins[island %in% in_island()]
}
if (length(in_sex()) > 0) {
penguins = penguins[sex %in% in_sex()]
}
ggplot(penguins) + geom_point(aes(x = `flipper_length_mm`, y = body_mass_g, colour = species)) + scale_colour_canva(palette = "Striking and energetic")
})
})
}
I am trying to update text and plot both with ActionButton click.
My Attempt-
library(shiny)
library(ggplot2)
library(shinyWidgets)
ui <- fluidPage(
actionGroupButtons(
inputIds = c("Bar", "Histogram", "Line"),
labels = list("Bar", "Histogram","Line"),
status = "danger",
fullwidth = T
),
plotOutput('plot',height = '563px'),
verbatimTextOutput('text')
)
server <- function(input, output) {
output$plot <- renderPlot({
if(req(input$Bar)!=0) {
isolate({
data <- iris
ggplot(data, aes(Species,Petal.Length)) +
geom_bar(stat="identity")
})
} else if(req(input$Histogram)>0){
isolate({
data <- iris
ggplot(data, aes(Petal.Length)) +
geom_histogram()
})
} else if(req(input$Line)>0){
isolate({
data <- iris
ggplot(data, aes(Petal.Length,Sepal.Length)) +
geom_line()
})
}
})
output$text <- renderText({
if(req(input$Bar)!=0) {
"Bar"
} else if(req(input$Histogram)>0){
"Histogram"
} else if(req(input$Line)>0){
"Line"
}
})
}
shinyApp(ui, server)
I want to change plot and text when the appropriate action button is clicked.
Here would be one way to do it.
In it's essence the approach is pointed out in the action button example no. 3 from RStudio.
library(shiny)
library(ggplot2)
library(shinyWidgets)
ui <- fluidPage(
actionGroupButtons(
inputIds = c("Bar", "Histogram", "Line"),
labels = list("Bar", "Histogram","Line"),
status = "danger",
fullwidth = T
),
plotOutput('plot',height = '563px'),
verbatimTextOutput('text')
)
server <- function(input, output) {
v <- reactiveValues(data = iris,
plot = NULL,
text = NULL)
observeEvent(input$Bar, {
v$plot <- ggplot(v$data, aes(Species,Petal.Length)) +
geom_bar(stat="identity")
v$text <- "Bar"
})
observeEvent(input$Histogram, {
data <- iris
v$plot <- ggplot(v$data, aes(Petal.Length)) +
geom_histogram()
v$text <- "Histogram"
})
observeEvent(input$Line, {
data <- iris
v$plot <- ggplot(v$data, aes(Petal.Length,Sepal.Length)) +
geom_line()
v$text <- "Line"
})
output$plot <- renderPlot({
if (is.null(v$plot)) return()
v$plot
})
output$text <- renderText({
if (is.null(v$text)) return()
v$text
})
}
shinyApp(ui, server)
Update
In case you are using Input filters on your data in a reactive, then you have to adjust the Approach above a litte:
library(shiny)
library(ggplot2)
library(shinyWidgets)
ui <- fluidPage(
selectInput(inputId = "species", label = "Select species:",
choices = unique(as.character(iris$Species)),
selected = "setosa"),
sliderInput("sepal_length", "Limit sepal length:",
round = 0,
min = range(iris$Sepal.Length)[1], max = range(iris$Sepal.Length)[2],
range(iris$Sepal.Length),
step = 0.1),
actionGroupButtons(
inputIds = c("Bar", "Histogram", "Line"),
labels = list("Bar", "Histogram","Line"),
status = "danger",
fullwidth = T
),
plotOutput('plot',height = '563px'),
verbatimTextOutput('text')
)
server <- function(input, output) {
data <- reactive({
temp <- subset(iris, Species == input$species)
subset(temp, Sepal.Length < input$sepal_length)
})
v <- reactiveValues(plot = NULL,
text = NULL)
observeEvent(input$Bar, {
v$plot <- ggplot(data(), aes(Species,Petal.Length)) +
geom_bar(stat="identity")
v$text <- "Bar"
})
observeEvent(input$Histogram, {
v$plot <- ggplot(data(), aes(Petal.Length)) +
geom_histogram()
v$text <- "Histogram"
})
observeEvent(input$Line, {
v$plot <- ggplot(data(), aes(Petal.Length,Sepal.Length)) +
geom_line()
v$text <- "Line"
})
output$plot <- renderPlot({
if (is.null(v$plot)) return()
v$plot
})
output$text <- renderText({
if (is.null(v$text)) return()
v$text
})
}
shinyApp(ui, server)
In the app below, I can switch back and forth between outputs generated by shiny::plotOutput and shiny::dataTableOutput. But when I select the option "DT", which generates a table using the DT::DTOutput function, the app gets stuck:
I can interact with the table (good)
Clicking "Load" does nothing (not good) even though it worked perfectly when non-DT output was selected before. Clicking "Load" should switch to selected output.
Is this a bug in DT? Is there a workaround?
UI:
library(shiny)
ui <- fluidPage(
uiOutput("ui_select"),
uiOutput("my_ui")
)
Server:
server <- function(input, output) {
output$ui_select = renderUI({
tagList(
selectInput("selectVal", "Select value", choices = c("gg", "dt", "DT")),
actionButton("loadVal", label = "Load")
)
})
observeEvent(input$loadVal, {
val = isolate({ input$selectVal })
output$my_output = switch(
val,
"gg" = renderPlot({ ggplot2::qplot(cyl, drat, data = mtcars) }),
"dt" = renderDataTable({ mtcars[1:3, 1:3] }),
"DT" = DT::renderDT({ mtcars[1:3, 1:3] })
)
output$my_ui = renderUI({
switch(
val,
"gg" = plotOutput("my_output"),
"dt" = dataTableOutput("my_output"),
"DT" = DT::DTOutput("my_output")
)
})
})
}
shinyApp(ui, server)
Its generally not a good idea to render much inside the observe as a memory leak can occur. have a look at the example below with a bigger diamonds dataset from the ggplot2 package.
library(shiny)
library(ggplot2)
data(diamonds)
ui <- fluidPage(
uiOutput("ui_select"),
uiOutput("my_ui")
)
server <- function(input, output) {
output$ui_select = renderUI({
tagList(
selectInput("selectVal", "Select value", choices = c("gg", "dt", "DT")),
actionButton("loadVal", label = "Load")
)
})
observeEvent(input$loadVal, {
val = isolate({ input$selectVal })
output$gg_output = renderPlot({ ggplot2::qplot(cyl, drat, data = mtcars) })
output$dt_output = renderDataTable({ diamonds })
output$DT_output = DT::renderDT({ diamonds })
output$my_ui = renderUI({
switch(
val,
"gg" = plotOutput("gg_output"),
"dt" = dataTableOutput("dt_output"),
"DT" = DT::DTOutput("DT_output")
)
})
})
}
shinyApp(ui, server)
Also I dont think its very efficient to create objects all the time, its best to render them once and simply switch and show what is required.
Proposed solution
library(shiny)
library(shinyjs)
library(ggplot2)
data(diamonds)
outputs <- c("gg_output","dt_output","DT_output")
hideoutputs <- function(output_names){
lapply(output_names, function(output_name){
hide(output_name)
})
}
ui <- fluidPage(
useShinyjs(),
uiOutput("ui_select"),
plotOutput("gg_output"),
dataTableOutput("dt_output"),
DT::DTOutput("DT_output")
)
server <- function(input, output, session) {
hideoutputs(outputs)
v <- reactiveValues(selection = "None")
output$ui_select <- renderUI({
tagList(
selectInput("selectVal", "Select value", choices = c("gg", "dt", "DT")),
actionButton("loadVal", label = "Load")
)
})
output$gg_output <- renderPlot({
qplot(cyl, drat, data = mtcars)
})
output$dt_output <- renderDataTable({
diamonds
})
output$DT_output <- DT::renderDT({
diamonds
})
observeEvent(input$loadVal, {
if(v$selection == input$selectVal){
return()
}
hideoutputs(outputs)
switch(
input$selectVal,
"gg" = show("gg_output"),
"dt" = show("dt_output"),
"DT" = show("DT_output")
)
v$selection <- input$selectVal
})
}
shinyApp(ui, server)
You're essentially defining multiple elements with the same ID. That's invalid HTML, and is bound to result in undefined behaviour. Sometimes defining multiple inputs/outpust with identical IDs seems to work, but it should never be done.
Giving each output its own ID solves this.
server <- function(input, output) {
output$ui_select = renderUI({
tagList(
selectInput("selectVal", "Select value", choices = c("gg", "dt", "DT")),
actionButton("loadVal", label = "Load")
)
})
observeEvent(input$loadVal, {
val = isolate({ input$selectVal })
output$gg_output = renderPlot({ ggplot2::qplot(cyl, drat, data = mtcars) })
output$dt_output = renderDataTable({ mtcars[1:3, 1:3] })
output$DT_output = DT::renderDT({ mtcars[1:3, 1:3] })
output$my_ui = renderUI({
switch(
val,
"gg" = plotOutput("gg_output"),
"dt" = dataTableOutput("dt_output"),
"DT" = DT::DTOutput("DT_output")
)
})
})
}
shinyApp(ui, server)
I've got a dropdown selector and a slider scale. I want to render a plot with the drop down selector being the source of data. - I've got this part working
I simply want the slider's max value to change based on which dataset is selected.
Any suggestions?
server.R
library(shiny)
shinyServer(function(input, output) {
source("profile_plot.R")
load("test.Rdata")
output$distPlot <- renderPlot({
if(input$selection == "raw") {
plot_data <- as.matrix(obatch[1:input$probes,1:36])
} else if(input$selection == "normalised") {
plot_data <- as.matrix(eset.spike[1:input$probes,1:36])
}
plot_profile(plot_data, treatments = treatment, sep = TRUE)
})
})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("Profile Plot"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("selection", "Choose a dataset:",
choices=c('raw', 'normalised')),
hr(),
sliderInput("probes",
"Number of probes:",
min = 2,
max = 3540,
value = 10)
),
mainPanel(
plotOutput("distPlot")
)
)
))
As #Edik noted the best way to do this would be to use an update.. type function. It looks like updateSliderInput doesnt allow control of the range so you can try using renderUI on the server side:
library(shiny)
runApp(list(
ui = bootstrapPage(
numericInput('n', 'Maximum of slider', 100),
uiOutput("slider"),
textOutput("test")
),
server = function(input, output) {
output$slider <- renderUI({
sliderInput("myslider", "Slider text", 1,
max(input$n, isolate(input$myslider)), 21)
})
output$test <- renderText({input$myslider})
}
))
Hopefully this post will help someone learning Shiny:
The information in the answers is useful conceptually and mechanically, but doesn't help the overall question.
So the most useful feature I found in the UI API is conditionalPanel() here
This means I could create a slider function for each dataset loaded and get the max value by loading in the data initially in global.R. For those that don't know, objects loaded into global.R can be referenced from ui.R.
global.R - Loads in a ggplo2 method and test data objects (eset.spike & obatch)
source("profile_plot.R")
load("test.Rdata")
server.R -
library(shiny)
library(shinyIncubator)
shinyServer(function(input, output) {
values <- reactiveValues()
datasetInput <- reactive({
switch(input$dataset,
"Raw Data" = obatch,
"Normalised Data - Pre QC" = eset.spike)
})
sepInput <- reactive({
switch(input$sep,
"Yes" = TRUE,
"No" = FALSE)
})
rangeInput <- reactive({
df <- datasetInput()
values$range <- length(df[,1])
if(input$unit == "Percentile") {
values$first <- ceiling((values$range/100) * input$percentile[1])
values$last <- ceiling((values$range/100) * input$percentile[2])
} else {
values$first <- 1
values$last <- input$probes
}
})
plotInput <- reactive({
df <- datasetInput()
enable <- sepInput()
rangeInput()
p <- plot_profile(df[values$first:values$last,],
treatments=treatment,
sep=enable)
})
output$plot <- renderPlot({
print(plotInput())
})
output$downloadData <- downloadHandler(
filename = function() { paste(input$dataset, '_Data.csv', sep='') },
content = function(file) {
write.csv(datasetInput(), file)
}
)
output$downloadRangeData <- downloadHandler(
filename = function() { paste(input$dataset, '_', values$first, '_', values$last, '_Range.csv', sep='') },
content = function(file) {
write.csv(datasetInput()[values$first:values$last,], file)
}
)
output$downloadPlot <- downloadHandler(
filename = function() { paste(input$dataset, '_ProfilePlot.png', sep='') },
content = function(file) {
png(file)
print(plotInput())
dev.off()
}
)
})
ui.R
library(shiny)
library(shinyIncubator)
shinyUI(pageWithSidebar(
headerPanel('Profile Plot'),
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("Raw Data", "Normalised Data - Pre QC")),
selectInput("sep", "Separate by Treatment?:",
choices = c("Yes", "No")),
selectInput("unit", "Unit:",
choices = c("Percentile", "Absolute")),
wellPanel(
conditionalPanel(
condition = "input.unit == 'Percentile'",
sliderInput("percentile",
label = "Percentile Range:",
min = 1, max = 100, value = c(1, 5))
),
conditionalPanel(
condition = "input.unit == 'Absolute'",
conditionalPanel(
condition = "input.dataset == 'Normalised Data - Pre QC'",
sliderInput("probes",
"Probes:",
min = 1,
max = length(eset.spike[,1]),
value = 30)
),
conditionalPanel(
condition = "input.dataset == 'Raw Data'",
sliderInput("probes",
"Probes:",
min = 1,
max = length(obatch[,1]),
value = 30)
)
)
)
),
mainPanel(
plotOutput('plot'),
wellPanel(
downloadButton('downloadData', 'Download Data Set'),
downloadButton('downloadRangeData', 'Download Current Range'),
downloadButton('downloadPlot', 'Download Plot')
)
)
))
I think you're looking for the updateSliderInput function that allows you to programmatically update a shiny input:
http://shiny.rstudio.com/reference/shiny/latest/updateSliderInput.html. There are similar functions for other inputs as well.
observe({
x.dataset.selection = input$selection
if (x.dataset.selection == "raw") {
x.num.rows = nrow(obatch)
} else {
x.num.rows = nrow(eset.spike)
}
# Edit: Turns out updateSliderInput can't do this,
# but using a numericInput with
# updateNumericInput should do the trick.
updateSliderInput(session, "probes",
label = paste("Slider label", x.dataset.selection),
value = c(1,x.num.rows))
})
Another alternative can be applying a renderUI approach like it is described in one of the shiny gallery examples:
http://shiny.rstudio.com/gallery/dynamic-ui.html