Creating inputs that depend on each other with Shiny and Flexdashboard - r

I have tried creating a drop-down that depends on a different widget ID.
In this app, the symbol drop-down-list depends on the input from the Stock Class chckboxGroupButtons()
I've successfully implemented that, but after inserting an eventReactive () that delays the reactive filtering and only starts filtering once "apply" is selected, the app shows an empty dataframe to start with.
Only AFTER clicking on either "Apply" or "Reset" then the app works the way it should.
I just need the unfiltered dataframe when rendering the app for the first time.
How do I fix this?
Code:
---
title: "Sample App"
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
runtime: shiny
---
library(flexdashboard)
library(shiny)
library(shinyWidgets)
library(shinyjs)
# Core
library(tidyverse)
library(lubridate)
# Make data
symbols <- purrr::cross_df(list(numbers = 1:90,letters = LETTERS))
symbols$symbol <- paste(symbols$numbers,symbols$letters,sep = " - ")
set.seed(123)
stock_prices_tbl <- tibble(
date = seq.Date(from = ymd("2018-01-01"), to = Sys.Date(), length.out = 90),
class = sample(c("marketing", "sales", "research"), size = 90, replace = TRUE),
symbol = sample(symbols$symbol,size = 90,replace = F),
adjusted = runif(n = 90,min = 0,90)
)
Sidebar {.sidebar}
---
# Allow shiny js
shinyjs::useShinyjs(rmd = T)
dateRangeInput(
inputId = "date_range",
label = h4("Date Range"),
start = min(stock_prices_tbl$date),
end = max(stock_prices_tbl$date),
min = min(stock_prices_tbl$date),
max = max(stock_prices_tbl$date),
startview = "month")
shinyWidgets::checkboxGroupButtons(
inputId = "class",
label = h4("Stock Class"),
choices = unique(stock_prices_tbl$class),
selected = unique(stock_prices_tbl$class),
checkIcon = list(
yes = icon("ok", lib = "glyphicon"),
no = icon("remove", lib = "glyphicon")
))
shiny::renderUI({
shinyWidgets::pickerInput(
inputId = "symbol",label = h4("Symbol"),
choices = unique(stock_prices_tbl[stock_prices_tbl$class %in% input$class,]$symbol),
selected = unique(stock_prices_tbl[stock_prices_tbl$class %in% input$class,]$symbol),
multiple = TRUE,
options = list(
`actions-box` = TRUE,
size = 10,
`selected-text-format` = "count",
`live-search` = TRUE
))
})
br()
hr()
br()
shiny::actionButton(inputId = "apply",label = "Apply",icon = shiny::icon("play"))
# Resetting app to default values:
actionButton(inputId = "reset", label = "Reset", icon = shiny::icon("sync"))
observeEvent(eventExpr = input$reset, handlerExpr = {
updateCheckboxGroupButtons(
session = session,
inputId = "class",
selected = unique(stock_prices_tbl$class))
updatePickerInput(
session = session,
inputId = "symbol",
selected = unique(stock_prices_tbl$symbol))
updateDateRangeInput(
session = session,
inputId = "date_range",
start = min(stock_prices_tbl$date),
end = max(stock_prices_tbl$date))
# We'll need to mimic a click when resetting our app to defaults
shinyjs::delay(ms = 300,expr = {shinyjs::click(
id = "apply" # The input id that you want to enforce when resetting to defaults
)
})
})
# Delay Reactions
stocks_reactive <- shiny::eventReactive(eventExpr = input$apply ,valueExpr = {
stock_prices_tbl %>%
filter(
between(date,input$date_range[1],input$date_range[2]) &
class %in% input$class &
symbol %in% input$symbol
)
},ignoreNULL = F, ignoreInit = F)
Column {data-width=1000}
---
renderPrint(expr = {stocks_reactive()})

Related

How to dispay two different graphs one below other using same input dataset in flexdashboard?

I'm trying to have two graphs in the same tab in flexdashboard. The two have the same input variable and should be selected by user but the output should be independent. I would like to have a choice to display one graph alone or the two together.
I found some resource for shiny but I've been struggling to implement them in my code. I'm providing an example of my code so far:
---
title: "Untitled"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
---
```{r}
df <- data.frame(
frequency = c(22,23,24,25,26,27),
transmission = c(91,92,93,94,95,96),
replicate = factor(c(1,2,3,4,5,6)),
power = c(20, 0, 5, 6, 40, 60)
)
```
```{r}
library("tidyverse")
library("xts")
library("fs")
library("plotly")
library("shiny")
library("shinyWidgets")
library("shinyjs")
library("shinydashboard")
library("flexdashboard")
```
Acoustic Power output
=================================
Sidebar{.sidebar data-width=400}
---------------------------------
**Exploring the acoustic data output**
This is an interactive dashboard to facilitate analysis of power measurements
<br>
**Scatterplot**
Choose the variables to be displayed.
```{r inputs_1, echo=FALSE}
# Inputs for all axis
selectInput(inputId = "x",
label = "X-Axis",
choices = names(df))
selectInput(inputId = "y",
label = "Y-Axis",
choices = names(df))
selectInput(inputId = "z",
label = "Colour by",
choices = names(df))
minvalue <- floor(min(df$frequency))
maxvalue <- ceiling(max(df$frequency))
sliderInput(
inputId ="freq_range",
label = "Select frequency range",
min = minvalue,
max = maxvalue,
value = c(minvalue, maxvalue)
)
```
**Single plots**
This can be used to display single plots and directly compare the output
```{r inputs_2, echo=FALSE}
# Picker Input Widget: PICK TRANSDUCER
shinyWidgets::pickerInput(
inputId = "pick_replicate",
label = "Pick replicates ",
choices = sort(unique(df$replicate)),
selected = unique(df$replicate),
multiple = TRUE # Allow multiple option
)
# Picker Input Widget: PICK REPLICATE
shinyWidgets::pickerInput(
inputId = "graph_select",
label = "Select graph",
choices = c("Graph 1", "Graph 2"),
multiple = TRUE
)
# Action button
actionButton(inputId = "apply",
label = "Apply",
icon = icon("play"),
width = '50%')
# Reset button
actionButton(inputId = "reset",
label = "Reset",
icon = icon("sync"),
width = '50%')
# Apply buttons
#
observeEvent(eventExpr = input$reset,# When button is clicked..
handlerExpr = { # ...this is executed
# Update picker widget: Transducer
updatePickerInput(
session = session,
inputId = "pick_replicate",
selected = unique(df$replicate)
)
# Update picker widget: Replicate
updatePickerInput(
session = session,
inputId = "graph_select",
selected = ""
)
#
# Delay and Mimic click on Apply button
shinyjs::delay(ms = 300, expr = {
shinyjs::click(id = "apply")
})
})
```
<br>
Row {.tabset}
-------------------------------------------
### Scatter plot
```{r, echo = F}
# Reactive Event: waits until a button (Apply) is clicked to run reactive code
filtered_df_grap2 <- eventReactive(
eventExpr = "Graph 2" %in% input$graph_select,
valueExpr = {
df %>%
filter(replicate %in% input$pick_replicate) %>%
filter(frequency >= input$freq_range[1] & frequency <= input$freq_range[2])
}
)
```
```{r,message = FALSE,echo = FALSE}
output$plotly_1 <- renderPlotly({
filtered_df_grap2() %>%
ggplot(aes_string(x = input$x, y = input$y,
colour = input$z))+
geom_point()+
theme_classic()
})
plotlyOutput(outputId= "plotly_1")
```
Row {.tabset}
-------------------------------------------
```{r, echo = F}
# Reactive Event: waits until a button (Apply) is clicked to run reactive code
filtered_df_grap1 <- eventReactive(
eventExpr = "Graph 1" %in% input$graph_select,
valueExpr = {
df %>%
filter(replicate %in% input$pick_replicate) %>%
filter(frequency >= input$freq_range[1] & frequency <= input$freq_range[2])
}
)
```
```{r,message = FALSE,echo = FALSE}
output$plotly_2 <- renderPlotly({
filtered_df_grap1() %>%
ggplot(aes_string(x = input$x, y = input$y,
colour = input$z))+
geom_point()+
theme_classic()
})
plotlyOutput(outputId= "plotly_2")
```
Any suggestion are welcomed
There are many ways you could do this. One method is to use Column and set the data-width. (You don't need Row at all.)
---
title: "Untitled"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
---
```{r}
df <- data.frame(
frequency = c(22,23,24,25,26,27),
transmission = c(91,92,93,94,95,96),
replicate = factor(c(1,2,3,4,5,6)),
power = c(20, 0, 5, 6, 40, 60)
)
```
```{r}
library("tidyverse")
library("xts")
library("fs")
library("plotly")
library("shiny")
library("shinyWidgets")
library("shinyjs")
library("shinydashboard")
library("flexdashboard")
```
Acoustic Power output
=================================
Sidebar{.sidebar data-width=400}
---------------------------------
**Exploring the acoustic data output**
This is an interactive dashboard to facilitate analysis of power measurements
<br>
**Scatterplot**
Choose the variables to be displayed.
```{r inputs_1, echo=FALSE}
# Inputs for all axis
selectInput(inputId = "x",
label = "X-Axis",
choices = names(df))
selectInput(inputId = "y",
label = "Y-Axis",
choices = names(df))
selectInput(inputId = "z",
label = "Colour by",
choices = names(df))
minvalue <- floor(min(df$frequency))
maxvalue <- ceiling(max(df$frequency))
sliderInput(
inputId ="freq_range",
label = "Select frequency range",
min = minvalue,
max = maxvalue,
value = c(minvalue, maxvalue)
)
```
**Single plots**
This can be used to display single plots and directly compare the output
```{r inputs_2, echo=FALSE}
# Picker Input Widget: PICK TRANSDUCER
shinyWidgets::pickerInput(
inputId = "pick_replicate",
label = "Pick replicates ",
choices = sort(unique(df$replicate)),
selected = unique(df$replicate),
multiple = TRUE # Allow multiple option
)
# Picker Input Widget: PICK REPLICATE
shinyWidgets::pickerInput(
inputId = "graph_select",
label = "Select graph",
choices = c("Graph 1", "Graph 2"),
multiple = TRUE
)
# Action button
actionButton(inputId = "apply",
label = "Apply",
icon = icon("play"),
width = '50%')
# Reset button
actionButton(inputId = "reset",
label = "Reset",
icon = icon("sync"),
width = '50%')
# Apply buttons
#
observeEvent(eventExpr = input$reset,# When button is clicked..
handlerExpr = { # ...this is executed
# Update picker widget: Transducer
updatePickerInput(
session = session,
inputId = "pick_replicate",
selected = unique(df$replicate)
)
# Update picker widget: Replicate
updatePickerInput(
session = session,
inputId = "graph_select",
selected = ""
)
#
# Delay and Mimic click on Apply button
shinyjs::delay(ms = 300, expr = {
shinyjs::click(id = "apply")
})
})
```
<br>
Column {data-width=1000}
-------------------------------------------
### Scatter plot
```{r, echo = F}
# Reactive Event: waits until a button (Apply) is clicked to run reactive code
filtered_df_grap2 <- eventReactive(
eventExpr = "Graph 2" %in% input$graph_select,
valueExpr = {
df %>%
filter(replicate %in% input$pick_replicate) %>%
filter(frequency >= input$freq_range[1] & frequency <= input$freq_range[2])
}
)
```
```{r,message = FALSE,echo = FALSE}
output$plotly_1 <- renderPlotly({
filtered_df_grap2() %>%
ggplot(aes_string(x = input$x, y = input$y,
colour = input$z))+
geom_point()+
theme_classic()
})
plotlyOutput(outputId= "plotly_1", width = "100%", height = "50%")
```
### Scatter plot
```{r, echo = F}
# Reactive Event: waits until a button (Apply) is clicked to run reactive code
filtered_df_grap1 <- eventReactive(
eventExpr = "Graph 1" %in% input$graph_select,
valueExpr = {
df %>%
filter(replicate %in% input$pick_replicate) %>%
filter(frequency >= input$freq_range[1] & frequency <= input$freq_range[2])
}
)
```
```{r,message = FALSE,echo = FALSE}
output$plotly_2 <- renderPlotly({
filtered_df_grap1() %>%
ggplot(aes_string(x = input$x, y = input$y,
colour = input$z)) +
geom_point() +
theme_classic()
})
plotlyOutput(outputId= "plotly_2", width = "100%", height = "50%")
```

Update new table with rows appended using actionButton in R Shiny

I have a Forecast table in Aurora, which I am able to read and filter-load using reactive. I am writing new rows to the table using an action button 'write_to_forecast_table', but I am not able to load the newly added row in the main table simultaneously.
tabPanel("Plant-Screen",
fluidRow(id='forecast_section',
column(width = 3, class='div-box-shadow',
tags$div(selectInput("fb_plant_input", label = 'Select Plant: ', choices= c(" All"), selected = NULL, multiple = FALSE, width = "100%"),
selectInput("fb_material_input", label = 'Commodity', choices = c(" All"), multiple=FALSE, width="100%"),
selectInput("fb_for_month_year", label = 'Procured for Month_Year', choices = c(" All"), multiple=FALSE, width="100%"),
br(),
tags$div(shinyWidgets::actionBttn(inputId = 'view_existing_forecasts', label='View Volume Forecast')),
tags$div(shinyWidgets::actionBttn(inputId = 'create_new_forecast', label='Create New Forecast')
),
bsModal(id="modal_demand_view",
title = "Create Volume Demand Forecast",
trigger = "create_new_forecast",
size="medium",
fluidRow(id = 'new_demand_form',
column(width = 12,
tags$div(style="display:contents;",
selectizeInput("selected_plant",
label = 'Plant',
options = list(placeholder = 'Select Plant'),
choices= unique(fb_plant_table$plant_name),
multiple=FALSE,
width="100%"),
br(),
selectizeInput("selected_material",
label = 'Commodity',
options = list(placeholder = 'Select Commodity'),
choices = unique(fb_material_table$commodity),
multiple=FALSE,
width="100%"),
br(),
airDatepickerInput("selected_month_year",
label = "Enter for Month-Year :",
value = lubridate::ymd(today()),
minDate = lubridate::ymd(today()) %m+% months(1),
maxDate = lubridate::ymd(today()) %m+% months(12),
view = "months",
minView = "months",
dateFormat = "yyyy-mm",
width = "50%",
autoClose = TRUE
),
br(),
numericInput("volume_requested",
label = "Enter Additional Volume",
value = 0,
width = "50%"),
br(),
selectizeInput("volume_unit", label = "Unit of Volume",
choices = c("pounds"),
multiple = FALSE,
width = "50%"),
br(),
selectInput("selected_supplier", label = "Supplier",
choices = "",
multiple = FALSE,
width = "50%")
)
)
),
br(),
tags$hr(),
tags$div(shinyWidgets::actionBttn(inputId = 'write_to_forecast_table',
label='New Volume Demand Created',
color="success",
style="material-flat")
)
)
)
),
column(width = 9, class='div-box-shadow',
tags$div(tags$h4 ('Volume Forecast Tabular View',
style="font-weight:bold;color: #ffd207;text-align: center;"
),
br(),
dataTableOutput("vol_forecast_meta_data") %>% shinycssloaders::withSpinner(color="#78620e")
)
Server Side:
#reading table from Aurora:
c <- dcon_iam()
vol_forecast_aurora <- DBI::dbGetQuery(c, 'select * from database_name.vol_forecast_aurora')
vol_forecast_aurora <- vol_forecast_aurora %>% group_by(plant_name, commodity, for_month_year) %>% mutate(cum_sum = cumsum(additional_volume))
DBI::dbDisconnect(c)
#Viewing forecast based on inputs selected from Select Input:
observeEvent(input$view_existing_forecasts, {
view_fc_reactive <- reactive({
vol_forecast_aurora %>%
filter(plant_name == input$fb_plant_input) %>%
filter(commodity == input$fb_material_input) %>%
filter(for_month_year == input$fb_for_month_year)
})
output$vol_forecast_meta_data <- DT::renderDataTable(view_fc_reactive(),
options = list(paging = FALSE, searching = FALSE),
rownames = FALSE)
})
#update table based on the new row added using Modal:
observeEvent(input$write_to_forecast_table, {
forecast_temp <- z$vol_forecast_aurora
forecast_temp$entered_by=input$user_id
forecast_temp$entered_on=lubridate::ymd(today())
forecast_temp$plant_name=input$selected_plant
forecast_temp$commodity=input$selected_material
forecast_temp$for_month_year=input$selected_month_year
forecast_temp$additional_volume=input$volume_requested
forecast_temp$unit_of_vol=input$volume_unit
forecast_temp$supplier=input$selected_supplier
forecast_temp = forecast_temp[, c('entered_by', 'entered_on', 'plant_name', 'commodity', 'for_month_year', 'additional_volume', 'unit_of_vol', 'supplier')]
c = dcon_iam()
write_to_caspian_aurora(c,
value= z$forecast_temp,
name="vol_forecast_aurora",
append = TRUE,
overwrite=FALSE,
row.names=FALSE
)
#removeModal('modal_demand_view')
showNotification({"Demand Forecast Submitted"})
DBI::dbDisconnect(c)
#reloading the data to the app:
c <- dcon_iam()
vol_forecast_aurora <- DBI::dbGetQuery(c, 'select * from spendanalytics_ico.vol_forecast_aurora')
vol_forecast_aurora <- vol_forecast_aurora %>% group_by(plant_name, commodity, for_month_year) %>% mutate(cum_sum = cumsum(additional_volume))
DBI::dbDisconnect(c)
})
I need help sorting the last part of the server: observeEvent(input$write_to_forecast_table, {})
Your problem is that the underlying data vol_forecast_aurora is only fetched once when the app is loaded (and that it is not reactive, so that the last lines in observeEvent(input$write_to_forecast_table only create a local object within the observer). Therefore, you don't see the changes when you update the DB within the app. I suggest that you store vol_forecast_aurora within a reactiveValues object, so that you can easily update it.
Untested code:
#reading table from Aurora:
c <- dcon_iam()
data <- reactiveValues(vol_forecast_aurora = DBI::dbGetQuery(c, 'select * from database_name.vol_forecast_aurora') %>% group_by(plant_name, commodity, for_month_year) %>% mutate(cum_sum = cumsum(additional_volume)))
DBI::dbDisconnect(c)
#Viewing forecast based on inputs selected from Select Input:
observeEvent(input$view_existing_forecasts, {
view_fc_reactive <- reactive({
data$vol_forecast_aurora %>%
filter(plant_name == input$fb_plant_input) %>%
filter(commodity == input$fb_material_input) %>%
filter(for_month_year == input$fb_for_month_year)
})
output$vol_forecast_meta_data <- DT::renderDataTable(view_fc_reactive(),
options = list(paging = FALSE, searching = FALSE),
rownames = FALSE)
})
#update table based on the new row added using Modal:
observeEvent(input$write_to_forecast_table, {
forecast_temp <- z$vol_forecast_aurora
forecast_temp$entered_by=input$user_id
forecast_temp$entered_on=lubridate::ymd(today())
forecast_temp$plant_name=input$selected_plant
forecast_temp$commodity=input$selected_material
forecast_temp$for_month_year=input$selected_month_year
forecast_temp$additional_volume=input$volume_requested
forecast_temp$unit_of_vol=input$volume_unit
forecast_temp$supplier=input$selected_supplier
forecast_temp = forecast_temp[, c('entered_by', 'entered_on', 'plant_name', 'commodity', 'for_month_year', 'additional_volume', 'unit_of_vol', 'supplier')]
c = dcon_iam()
write_to_caspian_aurora(c,
value= z$forecast_temp,
name="vol_forecast_aurora",
append = TRUE,
overwrite=FALSE,
row.names=FALSE
)
#removeModal('modal_demand_view')
showNotification({"Demand Forecast Submitted"})
DBI::dbDisconnect(c)
#reloading the data to the app:
c <- dcon_iam()
vol_forecast_aurora_local <- DBI::dbGetQuery(c, 'select * from spendanalytics_ico.vol_forecast_aurora')
data$vol_forecast_aurora <- vol_forecast_aurora_local %>% group_by(plant_name, commodity, for_month_year) %>% mutate(cum_sum = cumsum(additional_volume))
DBI::dbDisconnect(c)
})

Issue in inserting value with rhandsontable

Thanks for taking your valuable time to pitch in into this question. :-)
I'm building a shiny app that would take user inputs through rhandsontable and save it as a .rds file for data persistence.
The code is as follows:
Global.r
library(shiny)
library(shinydashboard)
library(shinycssloaders
library(rhandsontable)
library(htmltools)
library(plotly)
library(shinyjs)
library(tidyverse)
library(DT)
# Reads the data stored already
raw_data_projects <- readRDS("Projects.rds")
# code to refresh app so as to display the newly added data
jsResetCode <- "shinyjs.reset = function() {history.go(0)}"
ui.R
dashboardPage(skin = "black",
dashboardHeader(dropdownMenuOutput("dropdownmenu"),title = "PMO Dashboard",
tags$li(div(img(src = 'TechM_logo.png',
height = "35px"),
style = "padding-top:10px; padding-bottom:10px;"),
class = "dropdown"),dropdownMenuOutput("msgOutput")) ,
dashboardSidebar(
sidebarMenu(
menuItem("Home", tabName = "home", icon = icon("home")),
menuItem("Projects", tabName = "pros", icon = icon("briefcase")),
menuItem("About Team", tabName = "teamstr", icon = icon("user-friends")),
menuItem("Training & Skills",tabName = "skills",icon = icon("book"))
)),
dashboardBody(
useShinyjs(), # Include shinyjs in the UI
extendShinyjs(text = jsResetCode),
tags$link(rel = "stylesheet", type = "text/css", href = "style_2.css"),
tabItems(
tabItem(tabName = "pros",
fluidPage(tabBox(width = "500px",
tabPanel("Metrics",
fluidRow(
valueBoxOutput("Completed", width = 3),
valueBoxOutput("WIP", width = 3),
valueBoxOutput("Delayed", width = 3),
valueBoxOutput("OnHold", width = 3)
),
fluidRow(
box(plotlyOutput("Project_category"), width = 4,solidHeader = TRUE, status = "primary", title = "Project Category", collapsible = TRUE),
box(plotlyOutput("Project_status"), width = 8,solidHeader = TRUE, status = "primary", title = "Project Status", collapsible = TRUE),
box(plotlyOutput("Complexity"), width = 4,solidHeader = TRUE, status = "primary", title = "Project Complexity", collapsible = TRUE),
box(plotlyOutput("Audits"), width = 4,solidHeader = TRUE, status = "primary", title = "Audit Status", collapsible = TRUE)
)),
tabPanel("Data",
box(withSpinner(rHandsontableOutput("Projects")), width = 12),
actionButton("saveBtnProjects", "Save Projects", icon = icon("save")),
actionButton("BtnResetProjects", "Reset Filters", icon = icon("eraser")))))
)))
server.r
shinyServer(function(input, output, session){
dt_projects <- reactive({ raw_data_projects })
vals <- reactiveValues()
output$Projects <- renderRHandsontable({
rhandsontable(dt_projects(), readOnly = FALSE, search = TRUE, selectCallback = TRUE ) %>%
hot_cols(columnSorting = TRUE, manualColumnMove = TRUE, manualColumnResize = TRUE ) %>%
hot_table(highlightRow = TRUE, highlightCol = TRUE) %>%
#hot_col("PROJECT.STATUS", renderer = text_renderer, type = "autocomplete") %>%
hot_rows(fixedRowsTop = 1)
})
# on click of button the file will be saved to the working directory
observeEvent(input$saveBtnProjects,
#write.csv(hot_to_r(input$Projects), file = "./Data/project_tracker.csv",row.names = FALSE)
saveRDS(hot_to_r(input$Projects),"Projects.rds")
)
# refresh the page
observeEvent(input$saveBtnProjects, {js$reset()})
})
So when I run the app I get the table I desire as below:
As we can see, as I was inserting values to the first column, all the other columns greyed out and I couldn't insert any values into it. Please help me with this issue.
Also please suggest if my code will display the data reactively as soon as I save the data by pressing Save Projects button.
Thanks a ton in advance!!
P.S : I have included the server code only for the table considering the length of the question leaving the code of other tabs. But still this code is reproducible.

R Shiny - unexpected behaviour of updateSelectizeInput with observer

I have a selectizeInput that can take multiple values (here: names of datasets). The current state of this input is monitored by an observeEvent, which renders the corresponding datatables and dynamically populates a tabsetPanel with the outputs. It all works fine when I choose new values directly in the input field. However, when I supply multiple new values with the updateSelectizeInput function, all tabs contain the same dataframe corresponding to the last value in the selected argument.
The example below illustrates the problem. The UI reacts as expected when using the input field, but when pressing the "Add all at once" button all tabs contain the same dataframe.
library(shiny)
library(shinyWidgets)
library(shinyjs)
library(DT)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectizeInput(inputId = "dataframes", label = "select dataframes", choices = c("iris", "mtcars", "DNase", "ChickWeight"), multiple = TRUE),
actionButton(inputId = "add_all", label = "Add all at once")
),
mainPanel(tabsetPanel(id = "df_tabset"))
)
)
server <- function(input, output, session) {
tables <- reactiveValues(iris = iris, mtcars = mtcars, DNase = DNase, ChickWeight = ChickWeight,
df_tabset = NULL) # keeps track of currently displayed tables
observeEvent(input$dataframes, {
if (length(input$dataframes) > length(tables$df_tabset)) { # new dataframes are selected
new_dfs = setdiff(input$dataframes, tables$df_tabset)
for(df in new_dfs){
output[[df]] = renderDT(tables[[df]], editable = T, rownames = F, options = list(dom = "t")) # DOES NOT WORK AS EXPECTED IF THERE is > 1 NEW DF
appendTab(inputId = "df_tabset", select = TRUE,
tabPanel(title = df, value = df, DTOutput(outputId = df))
)
}
tables$df_tabset = input$dataframes # update
} else {
df = tables$df_tabset[! tables$df_tabset %in% input$dataframes]
removeTab(inputId = "df_tabset", target = df)
tables$df_tabset = input$dataframes
}
}, ignoreNULL = FALSE, ignoreInit = TRUE)
observeEvent(input$add_all, {
updateSelectizeInput(session, "dataframes", selected = c("iris", "mtcars", "DNase", "ChickWeight"))
})
}
shinyApp(ui = ui, server = server)
You have to use local (see here).
observeEvent(input$dataframes, {
if (length(input$dataframes) > length(tables$df_tabset)) { # new dataframes are selected
new_dfs = setdiff(input$dataframes, tables$df_tabset)
for(df in new_dfs){
local({
.df <- df
output[[.df]] = renderDT(tables[[.df]], editable = TRUE,
rownames = FALSE, options = list(dom = "t"))
})
appendTab(inputId = "df_tabset", select = TRUE,
tabPanel(title = df, value = df, DTOutput(outputId = df))
)
}
tables$df_tabset = input$dataframes # update
} else {
df = tables$df_tabset[! tables$df_tabset %in% input$dataframes]
removeTab(inputId = "df_tabset", target = df)
tables$df_tabset = input$dataframes
}
}, ignoreNULL = FALSE, ignoreInit = TRUE)

Shiny radio button not getting rendered initially when the app starts

I am doing some timeseries analysis and have created a shiny app where when the app starts sample timeseries data is uploaded or the user can upload csv dataset from his local directory....
Sample Dataset:
df
month passengers
1 01-01-2000 2072798
2 01-02-2000 2118150
3 01-03-2000 2384907
4 01-04-2000 2260620
5 01-05-2000 2386165
6 01-06-2000 2635018
7 01-07-2000 2788843
8 01-08-2000 2942082
9 01-09-2000 2477000
10 01-10-2000 2527969
11 01-11-2000 2161170
12 01-12-2000 2175314
13 01-01-2001 2307525
14 01-02-2001 2196415
15 01-03-2001 2545863
library(signal)
library(shiny)
library(AnomalyDetection) #devtools::install_github("twitter/AnomalyDetection")
library(ggplot2)
# Define UI for application that draws a histogram
library(shinydashboard)
library(shinycssloaders)
library(googleVis)
shinyUI(dashboardPage(skin = "green",
dashboardHeader(title = "Anomaly Detection in Time series",
titleWidth = 350),
dashboardSidebar(
sidebarUserPanel("Nishant Upadhyay",
image = "nishantcofyshop.jpg"
),
sidebarMenu(
menuItem("Data", tabName = "data", icon = icon("database")),
menuItem("Filters", tabName = "filter", icon = icon("filter")),
menuItem("Anomalies", tabName = "anomaly", icon = icon("check")),
#menuItem("Save Data", tabName = "save", icon = icon("save"))
menuItem("About The App", tabName = "Help", icon = icon("info-circle"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "data",
fluidRow(
box(
title = "Data scatter Chart",
status = "primary",
solidHeader = T,
collapsible = T,
width = 12,
shinycssloaders::withSpinner(htmlOutput("dataChart"),type = getOption("spinner.type", default = 8),color = "red")
)
),
fluidRow(
box(
radioButtons(
"data_input","",
choices = list("Load sample data" = 1,
"Upload csv file" = 2
)
),
conditionalPanel(
condition = "input.data_input=='1'",
h5("Sample dataset of Lebron James basketball shots over the years")
),
conditionalPanel(
condition = "input.data_input=='2'",
fileInput('file1', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'text/tab-separated-values',
'text/plain',
'.csv',
'.tsv'
)),
checkboxInput('header', 'Header', TRUE),
radioButtons('sep', 'Separator',
c(Comma=',',
Semicolon=';',
Tab='\t'),','),
radioButtons('quote', 'Quote',
c('None'='',
'Double Quote'='"',
'Single Quote'="'"),
'')
),
title = "Select Dataset",
status = "info",
solidHeader = T,
collapsible = T
),
box(
title = "Data",
status = "info",
solidHeader = T,
collapsible = T,
shinycssloaders::withSpinner(htmlOutput('contents'),type = getOption("spinner.type", default = 8),color = "red")
)# end of box
)## end of Fluid row
), ## end of tab item
tabItem(
tabName = "filter",
fluidRow(
box(
title = "Data Chart",
status = "primary",
solidHeader = T,
collapsible = T,
width = 12,
shinycssloaders::withSpinner(htmlOutput('dataChartFiltered'),type = getOption("spinner.type", default = 8),color = "red")
)
),
fluidRow(
box(
title = "Filters",
status = "info",
solidHeader = T,
collapsible = T,
width = 4,
radioButtons("filt", NULL,
c("None" = "none",
"Butterworth" = "butt",
"Type-II Chebyshev" = "cheby2")),
submitButton("Filter")
),
box(
title = "Butterworth",
status = "info",
solidHeader = T,
collapsible = T,
width = 4,
textInput("buttern", label = "Filter Order", value = "3"),
textInput("butterf", label = "Critical Frequencies", value = "0.1"),
radioButtons("buttert", "Type",
c("Low-Pass" = "low",
"High-Pass" = "high"))
),
box(
title = "Chebyshev",
status = "info",
solidHeader = T,
collapsible = T,
width = 4,
textInput("chebyn", label = "Filter Order", value = "5"),
textInput("chebyd", label = "dB of Pass Band", value = "20"),
textInput("chebyf", label = "Critical Frequencies", value = "0.2"),
radioButtons("chebyt", "Type",
c("Low-Pass" = "low",
"High-Pass" = "high"))
)
)
)
) ## end of tab items
) ## end of Dashboard
)
)
shinyServer(function(input, output){
dataframe<-reactive({
if (input$data_input == 1) {
tab <- read.csv("df.csv",header = T,stringsAsFactors = F)
} else if (input$data_input == 2) {
inFile <- input$file1
if (is.null(inFile))
return(data.frame(x = "Select your datafile"))
tab = read.csv(inFile$datapath, header = input$header,
sep = input$sep, quote = input$quote)
}
tt <- tryCatch(as.POSIXct(tab[,1]),error=function(e) e, warning=function(w) w)
if (is(tt,"warning") | is(tt,"error")) {
tab$Old = tab[,1]
tab[,1] = as.POSIXct(1:nrow(tab), origin = Sys.time())
} else {
tab[,1] = as.POSIXct(tab[,1])
}
tab
})
output$dataChart <- renderGvis({
if (!is.null(dataframe()))
gvisLineChart(dataframe()[,c(1,2)], xvar = colnames(dataframe())[1], yvar = colnames(dataframe())[2],
options = list(
crosshair.trigger = 'selection',
enableInteractivity = TRUE,
hAxis.maxTextLines = 10,
tooltip.trigger = 'none'
))
})
output$contents <- renderGvis({
if (!is.null(dataframe()))
gvisTable(dataframe(),
options = list(page='enable'))
})
output$dataChartFiltered <- renderGvis({
if (input$filt == "none") {
return(NULL)
} else if (input$filt == "butt") {
bf <- butter(as.numeric(input$buttern), as.numeric(input$butterf), type = input$buttert)
filtered = data.frame(timestamp = dataframe()[,1],
count = as.numeric(filter(bf, dataframe()[,2])))
gvisLineChart(filtered, xvar = colnames(filtered)[1], yvar = colnames(filtered)[2],
options = list(
crosshair.trigger = 'selection',
enableInteractivity = TRUE,
hAxis.maxTextLines = 10,
tooltip.trigger = 'none'
))
} else if (input$filt == "cheby2") {
ch <- cheby2(as.numeric(input$chebyn), as.numeric(input$chebyd),
as.numeric(input$chebyf), type = input$chebyt)
filtered = data.frame(timestamp = dataframe()[,1],
count = as.numeric(filter(ch, dataframe()[,2])))
gvisLineChart(filtered, xvar = colnames(filtered)[1], yvar = colnames(filtered)[2],
options = list(
crosshair.trigger = 'selection',
enableInteractivity = TRUE,
hAxis.maxTextLines = 10,
tooltip.trigger = 'none'
))
}
})
})
The problem i am facing is that once the shiny app is executed , the sample data is loaded properly as the this data is placed in the app folder in the directory (one can use R inbuilt data set or use the data i gave in the start) and subsequently all steps gets executed properly.
But if i want to upload some other csv file from local directory, the upload button selection does not get activated even after selecting it.But,in fact, if one goes to the second menu item in the sidebar panel i.e. filter tab and clicks on the filter button (under Filters box ) and then if i go back to Data menu in the sidebar panel again, i can see that now my upload csv file button has got activated and now i can browse the csv file in local directory and upload the same into the app and now everything works fine.
It seems somewhere the condition that makes the upload file button is not getting active initially when the app opens....
Need help to sort out the issue...Sorry for posting large chunk of code....
conditionalPanel and submitButton do not work well together. Replace your submitButton("Filter") with actionButton("Filter", "").
EDIT:
As per the comment, for the plot to be generated only after the actionButton is clicked you can put output$dataChartFiltered inside observeEvent of Filter with isolate for `input objects as follows:
observeEvent(input$Filter,{
output$dataChartFiltered <- renderGvis({
if (isolate(input$filt) == "none") {
return(NULL)
} else if (isolate(input$filt) == "butt") {
bf <- butter(as.numeric(isolate(input$buttern)), as.numeric(isolate(input$butterf)), type = isolate(input$buttert))
filtered = data.frame(timestamp = dataframe()[,1],
count = as.numeric(filter(bf, dataframe()[,2])))
gvisLineChart(filtered, xvar = colnames(filtered)[1], yvar = colnames(filtered)[2],
options = list(
crosshair.trigger = 'selection',
enableInteractivity = TRUE,
hAxis.maxTextLines = 10,
tooltip.trigger = 'none'
))
} else if (isolate(input$filt) == "cheby2") {
ch <- cheby2(as.numeric(isolate(input$chebyn)), as.numeric(isolate(input$chebyd)),
as.numeric(isolate(input$chebyf)), type = isolate(input$chebyt))
filtered = data.frame(timestamp = dataframe()[,1],
count = as.numeric(filter(ch, dataframe()[,2])))
gvisLineChart(filtered, xvar = colnames(filtered)[1], yvar = colnames(filtered)[2],
options = list(
crosshair.trigger = 'selection',
enableInteractivity = TRUE,
hAxis.maxTextLines = 10,
tooltip.trigger = 'none'
))
}
})
})

Resources