shiny: add/remove time-series to dygraphs upon input values - shiny

I'm building a shiny app that would display in dygraphs a basic dataset and then offer an option to add new time series upon selecting the checkbox input. However, as I coded it now, I'm 'stuck' at the original dataset and unable to add/remove new content. Any hints how to solve this are very welcome, thanks.
library(shinydashboard)
library(dygraphs)
library(dplyr)
ui <-dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
useShinyjs(),
checkboxGroupInput(inputId = 'options',
label = 'Choose your plot(s)',
choices = list("mdeaths" = 1,
"ldeaths" = 2)
),
uiOutput("Ui1")
)
)
server <- function(input, output, session) {
output$Ui1 <- renderUI({
output$plot1 <- renderDygraph({
final_ts <- ldeaths
p <- dygraph(final_ts, main = 'Main plot') %>%
dygraphs::dyRangeSelector()
if(1 %in% input$options) {
final_ts <- cbind(final_ts, mdeaths)
p <- p %>%
dySeries('mdeaths', 'Male Deaths')
} else if(2 %in% input$options) {
final_ts <- cbind(final_ts, fdeaths)
p <- p %>%
dySeries('fdeaths', 'Female Deaths')
}
p
})
dygraphOutput('plot1')
})
}
shinyApp(ui, server)

I'd suggest to dynamically filter the data based on the user selection instead of dynamically adding/removing traces from the plot:
library(shinydashboard)
library(shinyjs)
library(dygraphs)
library(dplyr)
lungDeaths <- cbind(ldeaths, mdeaths, fdeaths)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
useShinyjs(),
selectizeInput(
inputId = "options",
label = "Choose your trace(s)",
choices = colnames(lungDeaths),
selected = colnames(lungDeaths)[1],
multiple = TRUE,
options = list('plugins' = list('remove_button'))
),
uiOutput("Ui1")
)
)
server <- function(input, output, session) {
output$Ui1 <- renderUI({
filteredLungDeaths <- reactive({
lungDeaths[, input$options]
})
output$plot1 <- renderDygraph({
p <- dygraph(filteredLungDeaths(), main = 'Main plot') %>%
dygraphs::dyRangeSelector()
if('mdeaths' %in% colnames(filteredLungDeaths())){
p <- dySeries(p, 'mdeaths', 'Male Deaths')
}
if('fdeaths' %in% colnames(filteredLungDeaths())){
p <- dySeries(p, 'fdeaths', 'Female Deaths')
}
p
})
dygraphOutput('plot1')
})
}
shinyApp(ui, server)

Related

Shiny actionbutton to set a customized default

In this shiny App (code below), I need that the button labeled 'Customized' returns:
Select var X: disp
Select var Y: drat
Point size: 1.0
This necessity is a bit similar to the reset button available on the R package 'shinyjs', with the diference of that the reset button returns to the code's default.
library(shiny)
library(shinyjs)
shinyApp(
ui <- fluidPage(
sidebarPanel(
fluidRow(
shinyjs::useShinyjs(),
id = "panel_vars",
# Buttons
uiOutput("varx"),
uiOutput("vary"),
numericInput("ptSize", "Point size",
min=.1, max=5, value = 2),
actionButton("p1", 'Reset variables XY'),
helpText(""),
actionButton("p2", 'Customized')
)
),
mainPanel(
plotOutput("plot")
)
),
server <- function(input, output) {
getModel <- reactive({
names(mtcars)
})
output$varx <- renderUI({
selectInput("varsel.x", "Select var X",
choices = as.list(getModel()), multiple = F)
})
output$vary <- renderUI({
selectInput("varsel.y", "Select var Y",
choices = as.list(getModel()), multiple = F)
})
observeEvent(input$p1, {
shinyjs::reset("panel_vars")
})
output$plot <- renderPlot({
p <- mtcars %>% ggplot(aes_string(x=input$varsel.x, y=input$varsel.y))+
geom_point(size=input$ptSize)
p
})
}
)
You can simply use updateSelectInput and updateNumericInput to do so:
library(shiny)
library(shinyjs)
library(dplyr)
library(ggplot2)
shinyApp(
ui <- fluidPage(
sidebarPanel(
fluidRow(
shinyjs::useShinyjs(),
id = "panel_vars",
# Buttons
uiOutput("varx"),
uiOutput("vary"),
numericInput("ptSize", "Point size",
min=.1, max=5, value = 2),
actionButton("p1", 'Reset variables XY'),
helpText(""),
actionButton("p2", 'Customized')
)
),
mainPanel(
plotOutput("plot")
)
),
server <- function(input, output,session) {
getModel <- reactive({
names(mtcars)
})
output$varx <- renderUI({
selectInput("varsel.x", "Select var X",
choices = as.list(getModel()), multiple = F)
})
output$vary <- renderUI({
selectInput("varsel.y", "Select var Y",
choices = as.list(getModel()), multiple = F)
})
observeEvent(input$p1, {
shinyjs::reset("panel_vars")
})
output$plot <- renderPlot({
req(input$varsel.x,input$varsel.y,input$ptSize)
p <- mtcars %>% ggplot(aes_string(x=input$varsel.x, y=input$varsel.y))+
geom_point(size=input$ptSize)
p
})
observeEvent(input$p2, {
updateSelectInput(session,'varsel.x',selected = 'disp')
updateSelectInput(session,'varsel.y',selected = 'drat')
updateNumericInput(session, "ptSize", value = 1.0)
})
}
)

Data Table Using Modularity in RShiny

I'm trying to make a simple Shiny dashboard using the iris dataset in R.
What I accomplished so far: The current dashboard has two dropdowns. One that filters the Species column and one for the subspecies column that's dependent on the first dropdown. These two dropdowns work.
What's not working: Based on the two dropdowns, I'd like to see a datatable which should be a filtered dataset.
I think I'm using a wrong name space ?
Any advice would be of great help!
library(shiny)
library(DT)
library(dplyr)
## global.R
# Create sub_species column
iris2 <- iris %>%
mutate(
subspecies = case_when(
startsWith(as.character(Species), "setosa") ~ rep(c("setosa1", "setosa2"), length.out = n()),
startsWith(as.character(Species), "versicolor") ~ rep(c("versicolor1", "versicolor2"), length.out = n()),
startsWith(as.character(Species), "virginica") ~ rep(c("virginica1", "virginica2"), length.out = n())
)
)
## ui.R
fluidPage(
sidebarLayout(
sidebarPanel(
dropdownsUI("dropdowns")
),
mainPanel(
DT::dataTableOutput("table1")
)
)
)
## server.R
function(input, output, session) {
subspeciesServer("dropdowns")
data1 <- filteredDataServer("table1")
output$table1 <- DT::renderDataTable({
data1()
})
}
## modules.R
# UI logic
dropdownsUI <- function(id) {
ns <- NS(id)
# All input IDs in the function body must be wrapped with ns()
tagList(
selectInput(ns("speciesDropdown"), label = "Species:", choices = c("setosa", "versicolor", "virginica")),
uiOutput(ns("subspeciesDropdown")),
DT::dataTableOutput(ns("datatable"))
)
}
# Sub Species Dropdown logic
subspeciesServer <- function(id) {
moduleServer(id, function(input, output, session) {
dependent_subspecies <- reactive({
iris2 %>%
filter(Species == req(input$speciesDropdown)) %>%
pull(subspecies) %>%
unique()
})
output$subspeciesDropdown <- renderUI({
selectInput("vars_subspecies", "Sub Species:", choices = dependent_subspecies())
})
}
)
}
# Filtered data logic
filteredDataServer <- function(id) {
moduleServer(id, function(input, output, session) {
df <- reactive({
req(input$speciesDropdown, input$subspeciesDropdown)
iris2 %>%
# may be this what's causing the error ?
filter(Species %in% input$speciesDropdown & subspecies %in% input$vars_subspecies)
})
return(df)
}
)
}
Apart from namespace issue, you had a few other issues. You need to pass the reactive variables between modules. They are not available globally. Try this
library(shiny)
library(DT)
library(dplyr)
## global.R
# Create sub_species column
iris2 <- iris %>%
dplyr::mutate(
subspecies = case_when(
startsWith(as.character(Species), "setosa") ~ rep(c("setosa1", "setosa2"), length.out = n()),
startsWith(as.character(Species), "versicolor") ~ rep(c("versicolor1", "versicolor2"), length.out = n()),
startsWith(as.character(Species), "virginica") ~ rep(c("virginica1", "virginica2"), length.out = n())
)
)
## modules.R
# UI logic
dropdownsUI <- function(id) {
ns <- NS(id)
# All input IDs in the function body must be wrapped with ns()
tagList(
selectInput(ns("speciesDropdown"), label = "Species:", choices = c("setosa", "versicolor", "virginica")),
uiOutput(ns("subspeciesDropdown"))
#,DT::dataTableOutput(ns("datatable"))
)
}
# Sub Species Dropdown logic
subspeciesServer <- function(id) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
rv <- reactiveValues()
dependent_subspecies <- reactive({
iris2 %>%
filter(Species == req(input$speciesDropdown)) %>%
pull(subspecies) %>%
unique()
})
output$subspeciesDropdown <- renderUI({
req(dependent_subspecies())
selectInput(ns("vars_subspecies"), "Sub Species:", choices = dependent_subspecies())
})
observe({
rv$var1 <- input$speciesDropdown
rv$var2 <- input$vars_subspecies
})
return(rv)
}
)
}
# Filtered data logic
filteredDataServer <- function(id,sp,subsp,mydf) {
moduleServer(id, function(input, output, session) {
df <- reactive({
mydf %>% dplyr::filter(subspecies %in% subsp())
})
return(df)
}
)
}
## ui.R
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
dropdownsUI("dropdowns")
),
mainPanel(
DT::dataTableOutput("table1")
)
)
)
## server.R
server <- function(input, output, session) {
myvars <- subspeciesServer("dropdowns")
data1 <- filteredDataServer("table1", reactive(myvars$var1), reactive(myvars$var2),iris2)
output$table1 <- DT::renderDataTable({
datatable(req(data1()))
})
}
shinyApp(ui = ui, server = server)

Shiny App not reacting when clicking points in R

I am trying now since days to get my Shiny App working so that when I move my mouse to certain points in the plot they are displayed in a table but unfortunately it is not working.
I am not sure what I am doing wrong, can you help me?
border <- table$A < 0.03
ui <- fluidPage(
mainPanel(
plotOutput("Plot",click="plot_click"),
tableOutput("HitSpots")
)
)
server <- function(input, output){
output$Plot <- renderPlot({
ggplot(table,aes(x=table$A, y=table$B), colour=border)) +
geom_point()
})
hit <- reactive({
nearPoints(table, input$plot_click)
})
output$HitSpots <- renderTable({
hit()
}
}
shinyApp(ui = ui, server = server)
There are some problems with your parentheses. But the main problem is that you do ggplot(table, aes(x=table$A, y=table$B)), and then nearpoints is looking for columns named table$A and table$B. Do ggplot(table, aes(x=A, y=B)) instead.
library(shiny)
library(ggplot2)
table <- data.frame(
A = c(1,2,3),
B = c(3,2,1)
)
ui <- fluidPage(
mainPanel(
plotOutput("Plot", click="plot_click"),
tableOutput("HitSpots")
)
)
server <- function(input, output){
output$Plot <- renderPlot({
ggplot(table, aes(x=A, y=B)) + geom_point()
})
hit <- reactive({ nearPoints(table, input$plot_click) })
output$HitSpots <- renderTable({
hit()
})
}
shinyApp(ui = ui, server = server)

Shiny: calculate cumsum based on dygraphs' RangeSelector

I'm building a shiny app where I want to plot a dataset with one of the variables being a cumulative sum of another variable. The latter needs to be re-calculated every time the start date of dygraphs' dyRangeSelector changes. Below is a basic code without cumsum calculations. Commented out code is what I tried, with no success.
library(shinydashboard)
library(stringr)
library(zoo)
library(dplyr)
library(dygraphs)
ui <-dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
uiOutput("Ui1")
)
)
server <- function(input, output, session) {
output$Ui1 <- renderUI({
# date range observer
# values <- reactiveValues()
#
# observeEvent(input$plot1_date_window, {
# from <- as.Date(str_sub(input$plot1_date_window[[1]], 1, 10))
# })
## dygraphs plot
output$plot1 <- renderDygraph({
m_df <- data.frame(date=as.Date(zoo::as.yearmon(time(mdeaths))), Y=as.matrix(mdeaths))
# input_data <- m_df %>%
# filter(date >= values$from) %>%
# mutate(cumY = cumsum(Y))
input_xts <- xts(select(m_df, -date),
order.by = m_df$date)
#select(input_data, -date),
#order.by = input_data$date)
p <- dygraph(input_xts) %>%
dyRangeSelector()
p
})
## outputs
dygraphOutput('plot1')
})
}
shinyApp(ui, server)
UPDATE
I modified #Pork Chop's answer to be able to plot the cumulative values with other metrics on one graph, but I'm not even able to display the plot now:
library(xts)
library(shiny)
library(shinydashboard)
library(dygraphs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
dygraphOutput('plot1'),
textOutput("cumsum1")
)
)
server <- function(input, output, session) {
m_df <- data.frame(date=as.Date(zoo::as.yearmon(time(mdeaths))), Y=as.matrix(mdeaths))
subdata <- reactive({
cumsum(m_df$Y[m_df$date >= as.Date(input$plot1_date_window[1]) & m_df$date <= as.Date(input$plot1_date_window[2])])
})
output$plot1 <- renderDygraph({
req(input$plot1_date_window)
input_xts <- xts(select(m_df, -date), order.by = m_df$date)
subdata_xts <- xts(select(subdata(), - date), order.by = subdata()$date)
final_xts <- cbind(input_xts, subdata_xts)
dygraph(final_xts) %>%
dyRangeSelector()
})
output$cumsum1 <- renderText({
req(input$plot1_date_window)
subdata <- cumsum(m_df$Y[m_df$date >= as.Date(input$plot1_date_window[1]) & m_df$date <= as.Date(input$plot1_date_window[2])])
subdata
})
}
shinyApp(ui, server)
The problem with your updated code is, that you didn't keep the date information. Also once you start rendering a plot based on a change of the plot itself (recursion) it gets a little tricky. You have to make sure that re-rendering the plot doesn't trigger the rendering again or you'll end up in a loop. That's why I set retainDateWindow = TRUE. Besides that you don't want the plot to re-render right away after the first change of the slider that's why I debounced the subdata.
Nevertheless, using dygraphs you still have the problem, that when you add cumsum as a series your plot for dyRangeSelector is changed (y maximum of all series). Please see the following code:
library(xts)
library(shiny)
library(shinydashboard)
library(dygraphs)
library(dplyr)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
dygraphOutput('plot1')
)
)
server <- function(input, output, session) {
m_df <- data.frame(date=as.Date(zoo::as.yearmon(time(mdeaths))), Y=as.matrix(mdeaths))
subdata <- reactive({
if(!is.null(input$plot1_date_window)){
subdata <- m_df[m_df$date >= as.Date(input$plot1_date_window[1]) & m_df$date <= as.Date(input$plot1_date_window[2]), ]
subdata$cumsum <- cumsum(subdata$Y)
subdata$Y <- NULL
} else {
subdata <- NULL
}
return(subdata)
})
subdata_d <- subdata %>% debounce(100)
output$plot1 <- renderDygraph({
input_xts <- xts(select(m_df, -date), order.by = m_df$date)
if(is.null(subdata_d())){
final_xts <- input_xts
} else {
subdata_xts <- xts(select(subdata_d(), - date), order.by = subdata_d()$date)
final_xts <- cbind(input_xts, subdata_xts)
}
p <- dygraph(final_xts) %>% dySeries(name="Y") %>%
dyRangeSelector(retainDateWindow = TRUE)
if("cumsum" %in% names(final_xts)){
p <- dySeries(p, name="cumsum", axis = "y2")
}
p
})
}
shinyApp(ui, server)
Just as #PorkChop mentioned I'd recommend multiple outputs for this scenario. Furthermore, I'd suggest to have a look at library(plotly) and it's event_data().
This should do the job, I think it is cleaner to have separate outputs for your dashboard
library(xts)
library(shiny)
library(shinydashboard)
library(dygraphs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
dygraphOutput('plot1'),
textOutput("cumsum1")
)
)
server <- function(input, output, session) {
m_df <- data.frame(date=as.Date(zoo::as.yearmon(time(mdeaths))), Y=as.matrix(mdeaths))
output$plot1 <- renderDygraph({
input_xts <- xts(select(m_df, -date), order.by = m_df$date)
dygraph(input_xts) %>%
dyRangeSelector()
})
output$cumsum1 <- renderText({
req(input$plot1_date_window)
subdata <- cumsum(m_df$Y[m_df$date >= as.Date(input$plot1_date_window[1]) & m_df$date <= as.Date(input$plot1_date_window[2])])
subdata
})
}
shinyApp(ui, server)

How to add dynamic contents under those tabs create using renderUI in shinyR application

I am building an application in shiny R where in required tabs can be selected by the users and data relevant to those tabs will be displayed under it.
For example, in below sample application, mtcars data in .csv will be accepted as input parameter.User can select required column names in tabs field.Those colmns will be created as tabs.
Now, I want to show data pertaining to that column from .csv in the appropriate tab.Say, data from the column 'mpg' will be shown under 'mpg' tab.
But i am stuck here.Appreciate someone could tell me a way to display data from relevant column under appropriate tab ,dynamically.
Sample codes used is shown below:
write.csv(mtcars,'mtcars.csv')
#
library(shiny)
library(plyr)
library(dplyr)
ui <- pageWithSidebar(
headerPanel = headerPanel('data'),
sidebarPanel = sidebarPanel(fileInput(
'mtcars', h4('Uplaodmtcardata in csv format')
),
uiOutput('tabnamesui')),
mainPanel(uiOutput("tabsets"))
)
server <- function(input, output, session) {
mtcarsFile <- reactive({input$mtcars})
xxmtcars <-
reactive({
read.table(
file = mtcarsFile()$datapath,
sep = ',',
header = T,
stringsAsFactors = T
)
})
tabsnames <- reactive({
names(xxmtcars())
})
output$tabnamesui <- renderUI({
req(mtcarsFile())
selectInput(
'tabnamesui',
h5('Tab names'),
choices = as.list(tabsnames()),
multiple = T
)
})
tabnamesinput <- reactive({
input$tabnamesui
})
output$tabsets <- renderUI({
req(mtcarsFile())
tabs <-
reactive({
lapply(tabnamesinput(), function(x)
tabPanel(title = basename(x), dataTableOutput(x)))
})
do.call(tabsetPanel, c(tabs()))
})
output[['mpg']] <-
renderDataTable(as.data.frame(select(xxmtcars(), mpg)))#HOW TO AVOID THIS HARD CODING..?BASED ON THE TAB NAME DATA FROM RELEVANT COLUMN IN THE CSV TO BE RETURNED.
}
runApp(list(ui = ui, server = server))
#
Try this
library(shiny)
library(plyr)
library(dplyr)
library(rlang)
library(DT)
ui <- pageWithSidebar(
headerPanel = headerPanel('data'),
sidebarPanel = sidebarPanel(fileInput(
'mtcars', h4('Uplaodmtcardata in csv format')
),
uiOutput('tabnamesui')),
mainPanel(uiOutput("tabsets"))
)
server <- function(input, output, session) {
mtcarsFile <- reactive({input$mtcars})
xxmtcars <-
reactive({
read.table(
file = mtcarsFile()$datapath,
sep = ',',
header = T,
stringsAsFactors = FALSE
)
})
tabsnames <- reactive({
names(xxmtcars())
})
output$tabnamesui <- renderUI({
req(mtcarsFile())
selectInput(
'tabnamesui',
h5('Tab names'),
choices = as.list(tabsnames()),
multiple = T
)
})
tabnamesinput <- reactive({
input$tabnamesui
})
output$tabsets <- renderUI({
req(mtcarsFile())
tabs <-
reactive({
lapply(tabnamesinput(), function(x)
tabPanel(title = basename(x), dataTableOutput(x)))
})
do.call(tabsetPanel, c(tabs()))
})
observe(
lapply(tabnamesinput(), function(x) {
output[[x]] <- DT::renderDataTable({
t<-as.data.frame(dplyr::select(xxmtcars(), !! sym(x)) )
print(t)
datatable(t)
})
})
)
}
runApp(list(ui = ui, server = server))