How to display data frame for calculated difference between times? - r

I'm a beginner, which is worth mentioning at the beginning. I wanted to create an application in which the user enters an arbitrary date and, based on it, calculates the time between that date and the last activity of a person from the data table. if that time is greater than the value of input$disabled, which is the expected time of being offline, I would like to display all the information about those people. currently, I'm getting the following problem: Error in UseMethod: no applicable method for 'filter' applied to an object of class "c('reactiveExpr', 'reactive', 'function')" and for the second one: Error in UseMethod: no applicable method for 'mutate' applied to an object of class "difftime".
last_event has a character type and looks like this: "2019-12-22 00:00:0", which is why I overlay as.Date() on it. I am not sure if I used reactive() correctly, because this application is a work of trial and error. Can someone help me? I would be very grateful, because it is kinda frustrating for me right now.
last_event <- c("2019-12-26 00:00:00","2020-10-21 00:00:00","2020-05-27 00:00:01","2020-02-25 00:00:00","2020-10-09 00:00:00","2020-10-16 00:00:00","2019-12-01 00:00:01")
id <- c(1:7)
users_name <- c("Krox", "Minit", "Brulon", "Loc", "Mese02", "Robu78", "CoffeeMan")
data <- data.frame(id, users_name, last_event)
ui <- dashboardPage(
dashboardHeader(title = "X"),
dashboardSidebar(
dateInput(inputId = "date", label = "Podaj date : "),
sliderInput(inputId = "disabled", label = "Czas nieaktywnosci (msc): ", min = 6, max = 24, value = 12)),
dashboardBody(
dataTableOutput(outputId = "table")
))
server <- function(input, output){
reactive_data <- eventReactive(input$date, {
mutate(diff = (difftime(as.Date(input$date), as.Date(data$last_event)))/30)
data
})
output$table <- renderDataTable({
data <- reactive_data()
if (input$disabled){
data %>%
filter(diff > input$disabled)
}})
}
shinyApp(ui, server)
Also I try to write this code in another way:
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(readxl)
library(dplyr)
data <- read_excel(file.choose())
ui <- dashboardPage(
dashboardHeader(title = "X"),
dashboardSidebar(
dateInput(inputId = "date", label = "Podaj date : "),
sliderInput(inputId = "disabled", label = "Czas nieaktywnosci (msc): ", min = 6, max = 24, value = 12)),
dashboardBody(
dataTableOutput(outputId = "table")
))
server <- function(input, output){
data1 <- reactive(data %>%
mutate(diff = (difftime(as.Date(input$date)) - as.Date(data1$last_event))/30))
output$table <- renderDataTable(data1 %>%
filter(diff > input$disabled))
}
shinyApp(ui, server)

Please try the below:
last_event <- c("2019-12-26 00:00:00","2020-10-21 00:00:00","2020-05-27 00:00:01","2020-02-25 00:00:00","2020-10-09 00:00:00","2020-10-16 00:00:00","2019-12-01 00:00:01")
id <- c(1:7)
users_name <- c("Krox", "Minit", "Brulon", "Loc", "Mese02", "Robu78", "CoffeeMan")
data <- data.frame(id, users_name, last_event)
ui <- dashboardPage(
dashboardHeader(title = "X"),
dashboardSidebar(
dateInput(inputId = "date", label = "Podaj date : "),
sliderInput(inputId = "disabled", label = "Czas nieaktywnosci (msc): ", min = 6, max = 24, value = 12)),
dashboardBody(
dataTableOutput(outputId = "table")
))
server <- function(input, output){
reactive_data <- eventReactive(input$date, {
mutate(data, diff = (difftime(as.Date(input$date), as.Date(data$last_event)))/30)
})
output$table <- renderDataTable({
data <- reactive_data()
if (input$disabled){
data %>%
filter(diff > input$disabled)
}})
}
shinyApp(ui, server)
This line needed work:
mutate(data, diff = (difftime(as.Date(input$date), as.Date(data$last_event)))/30)
Alternatively:
data %>% mutate(diff = (difftime(as.Date(input$date), as.Date(data$last_event)))/30)
Update
for your second code example, see here:
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(readxl)
library(dplyr)
data <- read_excel(file.choose())
ui <- dashboardPage(
dashboardHeader(title = "X"),
dashboardSidebar(
dateInput(inputId = "date", label = "Podaj date : "),
sliderInput(inputId = "disabled", label = "Czas nieaktywnosci (msc): ", min = 6, max = 24, value = 12)),
dashboardBody(
dataTableOutput(outputId = "table")
))
server <- function(input, output){
data1 <- reactive(data %>%
mutate(diff = (difftime(as.Date(input$date), as.Date(data$last_event))/30)))
output$table <- renderDataTable(data1() %>%
filter(diff > input$disabled))
}
shinyApp(ui, server)

Actually I solved this problem by myself, but thank you all for answers. The final code looks like that:
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(readxl)
library(dplyr)
library(DT)
ui <- dashboardPage(
dashboardHeader(title = "X"),
dashboardSidebar(
dateInput(inputId = "date", label = "Choose date : "),
sliderInput(inputId = "disabled", label = "Choose time of inactivity: ", min = 6, max = 24, value = 12)),
dashboardBody(
dataTableOutput(outputId = "table")
))
server <- function(input, output){
data1 <- reactive(read_excel(file.choose()))
output$table <- renderDT({
data1() %>%
mutate(diff = (difftime(input$date, as.Date(last_event))/30)) %>%
filter(diff > input$disabled) %>%
select(-diff) %>%
DT::datatable(options(list(scrollX=TRUE)))
})
}
shinyApp(ui, server)

Related

dateInput in Shiny does not work with spinner

I am building an app with many charts and using spinners while waiting for them to generate.
I found if I add spinner to the charts, my date input no longer works.
I dont understand this behaviour, nor know how to fix it.
Here is my example:
library(data.table)
library(tidyverse)
library(shinydashboard)
library(highcharter)
library(lubridate)
library(shiny)
library(shinyWidgets)
library(shinycssloaders)
db <- mtcars
sidebar <- dashboardSidebar()
body <- dashboardBody(
h2("Test"),
box(title = "Date",width =12,
column(dateInput('startdate','',value = dmy("1/1/2017"), min = NULL, max = NULL,
format = "yyyy-mm-dd", startview = "month", weekstart = 0,language = "en", width = NULL),width = 3)
),
highchartOutput("hc")%>%withSpinner()
)
header <- dashboardHeader()
ui <- dashboardPage(header,sidebar,body)
server <- function(input, output, session) {
output$hc <- renderHighchart({
hc <- highchart() %>%
hc_add_series(name = "mpg", data = db$mpg) %>%
hc_add_series(name = "wt", data = db$wt)
hc
})
}
shinyApp(ui, server)
If I were to remove withSpinner(), I then can select the date.
I got a love-hate relationship with those spinners. Anyways: putting your graph in a fluidrow (and column) solved the problem for me:
library(data.table)
library(tidyverse)
library(shinydashboard)
library(highcharter)
library(lubridate)
library(shiny)
library(shinyWidgets)
library(shinycssloaders)
db <- mtcars
sidebar <- dashboardSidebar()
body <- dashboardBody(
h2("Test"),
box(title = "Date",width =12,
column(dateInput('startdate','',value = dmy("1/1/2017"), min = NULL, max = NULL,
format = "yyyy-mm-dd", startview = "month", weekstart = 0,language = "en", width = NULL),width = 3)
),
fluidRow(
column(
width = 12,
shinycssloaders::withSpinner(highchartOutput("hc"))
)
)
)
header <- dashboardHeader()
ui <- dashboardPage(header,sidebar,body)
server <- function(input, output, session) {
output$hc <- renderHighchart({
hc <- highchart() %>%
hc_add_series(name = "mpg", data = db$mpg) %>%
hc_add_series(name = "wt", data = db$wt)
hc
})
}
shinyApp(ui, server)
This is might suggest it was also weirdly applied to other aspects of your page rather than only your graph?

How do I get aggregated data for selected attributes from shiny app?

It would be great someone can help to solve below criteria.
Requirement details:-
How to pass multiple attributes dynamically to group_by/summaries clause to get aggregated data for selected attributes? in my case I am able to achieve the same by using below code, but it was restricted to 1 group by attribute and summary attribute. If I select multiple group by or summary attributes, it's throwing error.
library(dplyr)
library(data.table)
library(shiny)
library(DT)
df1 <- data.frame("name"=c("AAA","BBB","CCC"),"dept"=c("HR","HR","FIN"),"Salary"=c(1000,1345,5678),"Salary2"=c(4567,7896,5678))
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
pickerInput("Id0001","group by attributes",choices = unique(names(df1)),multiple = TRUE,options = list(`live-search` = TRUE)),
pickerInput("Id0002","summary attributes",choices = unique(names(df1)),multiple = TRUE,options = list(`live-search` = TRUE)),
actionButton("Id0003", "show data")
),
mainPanel( DT::DTOutput("data_tbl") )
)
)
server <- function(input,output,session){
reactive_string <- eventReactive(input$Id0003, {
if (input$Id0003 > 0) {
dt_agg_ui <<- df1 %>%
group_by(!!rlang::sym(input$Id0001)) %>%
summarise_at(vars(!!rlang::sym(input$Id0002)),funs(sum,n()))
}
dt_agg_ui
})
output$data_tbl <- DT::renderDT( {reactive_string()})
}
shinyApp(ui = ui, server = server)
Using dplyr::across and tidyselect::all_of this could be achieved like so:
library(dplyr)
library(data.table)
library(shiny)
library(shinyWidgets)
library(DT)
df1 <- data.frame("name"=c("AAA","BBB","CCC"),"dept"=c("HR","HR","FIN"),"Salary"=c(1000,1345,5678),"Salary2"=c(4567,7896,5678))
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
pickerInput("Id0001","group by attributes",choices = unique(names(df1)),multiple = TRUE,options = list(`live-search` = TRUE)),
pickerInput("Id0002","summary attributes",choices = unique(names(df1)),multiple = TRUE,options = list(`live-search` = TRUE)),
actionButton("Id0003", "show data")
),
mainPanel( DT::DTOutput("data_tbl") )
)
)
server <- function(input,output,session){
reactive_string <- eventReactive(input$Id0003, {
if (input$Id0003 > 0) {
dt_agg_ui <<- df1 %>%
group_by(across(all_of(input$Id0001))) %>%
summarise(across(all_of(input$Id0002), .fns = list(sum = sum, n = ~ n())))
}
dt_agg_ui
})
output$data_tbl <- DT::renderDT( {reactive_string()})
}
shinyApp(ui = ui, server = server)

How do I connect my summed tables to the date range in a Shiny App?

A simple table output of the count works when I change the dates, but my summed revenue table does not. I have tried using the group_by function and reactive but no to avail.
install.packages(c("shiny","shinydashboard","ggplot2","dplyr","tidyverse","scales","lubridate"))
#not all of these packages may be necesary. They are just the ones I have been playing with
df <- data.frame("Ship Date" = c(2020-01-05,2020-01-06,2020-01-05,2020-01-06,2020-01-05,2020-01-06
,2020-01-05,2020-01-06), "Team" = c("Blue","Blue","Green","Green"
,"Gold","Gold","Purple","Purple"), "Revenue" = c(20,15,17,23
,18,19,17,12))
ui <- fluidPage(
dashboardHeader(title = "Dashboard",titleWidth = 450),
dateRangeInput(
inputId = "daterange",
label = "Select the date range", start = Sys.Date(), end = Sys.Date(), min = min(df$`Ship Date`),
max = max(df$`Ship Date`), format = "yyyy/mm/dd", separator = "-" ),
textOutput("startdate"), textOutput("enddate"), textOutput("range"),
dashboardBody(
fluidRow(
column(width = 3, tableOutput('subdatavt')),
column(width = 3, tableOutput('subdatart'))
)))
server <- function(input, output, session) ({
output$startdate <- renderText({
as.character(input$daterange[1])
})
output$enddate <- renderText({
as.character(input$daterange[2])
})
output$range <- renderText({
paste("Selected date range is ", input$daterange[1], "to", input$daterange[2])
})
#volume by Team
output$subdatavt <- renderTable({
vt = subset(df, df$`Ship Date`>=input$daterange[1] & df$`Ship Date`<= input$daterange[2])
table(vt$Team)
})
#revenue by Team
# here is where I do not know how to go about it. I imagine something to do with the group_by function
Is this what you are looking for?
library(lubridate)
library(dplyr)
library(shiny)
library(shinydashboard)
df <- tibble("ShipDate" = as.Date(c("2020-01-05","2020-01-06","2020-01-05","2020-01-06","2020-01-05","2020-01-06","2020-01-05","2020-01-06")),
"Team" = c("Blue","Blue","Green","Green","Gold","Gold","Purple","Purple"),
"Revenue" = c(20,15,17,23,18,19,17,12))
ui <- fluidPage(
dashboardHeader(title = "Dashboard",titleWidth = 450),
dateRangeInput(
inputId = "daterange",
label = "Select the date range", start = Sys.Date(), end = Sys.Date(), min = min(df$ShipDate),
max = max(df$ShipDate), format = "yyyy/mm/dd", separator = "-" ),
textOutput("startdate"), textOutput("enddate"), textOutput("range"),
dashboardBody(
fluidRow(
column(width = 3, tableOutput('subdatavt')),
column(width = 3, tableOutput('subdatart'))
)))
server <- function(input, output, session) ({
output$startdate <- renderText({
as.character(input$daterange[1])
})
output$enddate <- renderText({
as.character(input$daterange[2])
})
output$range <- renderText({
paste("Selected date range is ", input$daterange[1], "to", input$daterange[2])
})
#volume by Team
output$subdatavt <- renderTable({
vt = df %>% filter(ShipDate >= input$daterange[1],
ShipDate <= input$daterange[2]) %>%
group_by(Team) %>%
summarise(Revenue = sum(Revenue), n=n()) %>%
na.omit
})
})
shinyApp(ui = ui, server = server)

How to add comment to a reactive data table in shiny

This question is an extension of the question I posted: this question
I created a dataframe with 3 columns: num, id and val. I want my shiny app to do the following:
a dataframe dat is filtered by num column
select an value from id column from dat (selectInput).
add text comment in a text box (textInput)
click on an action button
A new column called comment is created in the data table, text comments are added to the comment column in the row where id equals the value selected.
The code is below. I cannot figure out why it's not working.
Thank a lot in advance!
library(shiny)
library(DT)
dat = data.frame(num=rep(1:2, each=5), id=rep(LETTERS[1:5],2), val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10, selected='')),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df = reactive ({ dat %>% filter(num %in% input$selectNum) })
df_current <- reactiveVal(df())
observeEvent(input$button, {
req(df_current())
## update df by adding comments
df_new <- df_current()
df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment
df_current(df_new)
})
output$data <- DT::renderDataTable({
req(df_current())
DT::datatable(df_current(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
shinyApp(ui=ui, server=server)
Instead of using a reactive/eventReactive statement for df, it might be more natural to keep track of previously inputted comments in the Comment column using a reactiveVal object for df. See also the responses to this question: R Shiny: reactiveValues vs reactive. If you prefer to use a reactive/eventReactive statement for df it is probably better to work with a separate object to store previous input comments (instead of incorporating it into the reactive statement for df).
library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10)),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df_current <- reactiveVal(dat)
observeEvent(input$button, {
req(df_current(), input$selectID %in% dat$id)
## update df by adding comments
df_new <- df_current()
df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment
df_current(df_new)
})
output$data <- DT::renderDataTable({
req(df_current())
## filter df_current by 'selectNum'
df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]
## show comments if non-empty
showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))
DT::datatable(df_filtered,
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5,
columnDefs = list(
list(targets = ncol(df_filtered), visible = showComments)
)
)
)
})
}
shinyApp(ui=ui, server=server)
Edit: below an edited server function that using df_current <- reactive({...}) instead of df_current <- reactiveVal({...}) and defining a separate reactiveVal object to keep track of the comments.
server <- function(input, output, session) {
## initialize separate reactive object for comments
df_comments <- reactiveVal({
data.frame(
id = character(0),
Comment = character(0),
stringsAsFactors = FALSE
)
})
## reactive object df
df_current <- reactive({
## reactivity that df depends on
## currently df = dat does not change
df <- dat
## merge with current comments
if(nrow(df_comments()) > 0)
df <- merge(df, df_comments(), by = "id", all.x = TRUE)
return(df)
})
observeEvent(input$button, {
req(input$selectID)
## update df_comments by adding comments
df_comments_new <- rbind(df_comments(),
data.frame(id = input$selectID, Comment = input$comment)
)
## if duplicated id's keep only most recent rows
df_comments_new <- df_comments_new[!duplicated(df_comments_new$id, fromLast = TRUE), , drop = FALSE]
df_comments(df_comments_new)
})
output$data <- DT::renderDataTable({
req(df_current())
## filter df_current by 'selectNum'
df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]
## show comments if non-empty
showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))
DT::datatable(df_filtered,
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5,
columnDefs = list(
list(targets = ncol(df_filtered), visible = showComments)
)
)
)
})
}
There you have got a working example.
I think the thing is that you are trying to update a value through an observeEvent which is not good according to the documentation. ?observeEvent
Use observeEvent whenever you want to perform an action in response to an event. (Note that "recalculate a value" does not generally count as performing an action–see eventReactive for that.)
library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10, selected='')),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df_current = reactive({
df = dat %>% filter(num %in% input$selectNum)
if(input$button != 0) {
input$button
df[df$id %in% input$selectID, "Comment"] <- isolate(input$comment)
}
return(df)
})
output$data <- DT::renderDataTable({
req(df_current())
DT::datatable(df_current(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
}
shinyApp(ui=ui, server=server)
So you can either go with your reactive value or using eventReactive as stated in the doc.

Reactive select input to update table

I am trying to understand the reactive part in R shiny. In that process I am trying to update an output table based on the input change while selecting values from the age drop down. It seems to do it by the first value but when I change any value from the age drop down it won't update my table. The input I am using is chooseage. Below is the code which I am using.
library(shiny)
library(shinydashboard)
library(shinyBS)
library(knitr)
library(kableExtra)
library(shiny)
library(shinythemes)
ui <- dashboardPage(
dashboardHeader(disable = F, title = "PATH Study"),
dashboardSidebar(sidebarMenu(
menuItem(
"Population Filter",
uiOutput("choose_age")
)
)),
dashboardBody(box(
width = 12,
tabBox(
width = 12,
id = "tabBox_next_previous",
tabPanel("Initiation",
fluidRow(
box(
width = 5,
solidHeader = TRUE,
status = "primary",
tableOutput("smoke"),
collapsible = F
)
))
),
uiOutput("Next_Previous")
))
)
server <- function(input, output, session) {
# Drop-down selection box for which Age bracket to be selected
age_levels <- c("18 to 24 years old","25 to 34 years old","35 to 44 years old")
output$choose_age <- renderUI({
selectInput("selected_age", "Age", as.list(age_levels))
})
myData <- reactive({
with_demo_vars %>%
filter(age == input$choose_age) %>%
pct_ever_user(type = "SM")
})
output$smoke <-
renderTable({
head(myData())
})
}
shinyApp(ui = ui, server = server)
Here is a quick prototype for your task
library(shiny)
library(tidyverse)
library(DT)
# 1. Dataset
df_demo <- data.frame(
age = c(16, 17, 18, 19, 20),
name = c("Peter", "Mary", "Mike", "Nick", "Phillipe"))
# 2. Server
server <- function(input, output, session) {
# 1. UI element 'Age'
output$ui_select_age <- renderUI({
selectInput("si_age", "Age", df_demo$age)
})
# 2. Reactive data set
df_data <- reactive({
# 1. Read UI element
age_selected <- input$si_age
# 2. Filter data
df <- df_demo %>%
filter(age == age_selected)
# 3. Return result
df
})
# 3. Datatable
output$dt_table <- renderDataTable({
datatable(df_data())
})
}
# 3. UI
ui <- fluidPage(
fluidRow(uiOutput("ui_select_age")),
fluidRow(dataTableOutput("dt_table"))
)
# 4. Run app
shinyApp(ui = ui, server = server)
I think youre shinyApp is over-reactive, as all functions in the server are executed straight away, without waiting for any selected input. So either it will break down or behave weird. So you have to delay the reactivity with req(), validate() / need() or with any observeEvent or eventReactive() function.
Maybe this snippet might help you, although there would be several ways to achieve the desired behaviour.
library(shiny)
library(shinydashboard)
library(dplyr)
data(mtcars)
mtcars$age <- sample(x = c(10,20,30,40,50), size = nrow(mtcars), replace = T)
with_demo_vars <- mtcars
ui <- dashboardPage(
dashboardHeader(disable = F, title = "PATH Study"),
dashboardSidebar(sidebarMenu(
menuItem(text = "Population Filter",
uiOutput("choose_age")
)
)
),
dashboardBody(
tableOutput("smoke")
)
)
server <- function(input, output, session) {
output$choose_age <- renderUI({
selectInput("selected_age", "Age", with_demo_vars$age)
})
myData <- reactive({
with_demo_vars %>%
dplyr::filter(age == input$selected_age)
})
output$smoke <- renderTable({
req(input$selected_age)
head(myData())
})
}
shinyApp(ui = ui, server = server)

Resources