reactiveValues and Global Variables in Shiny - r

There seems to be some others who are confused by this same issue but after reading and attempting the solutions I found here, I am still stumped. Help!
I have a Shiny App that takes the difference between prices between two dates and returns a list of 4 tables one for each type of Product for each Date, and the same 4 tables for the Price Deltas of the two Dates.
(DATE1, DATE2, DELTA)
On my output screens after Calc, the tables remain empty until the user clicks on the inputSelectors which prompt the table to refresh.
I am still struggling to understand how to get the table to automatically refresh when the Calculation ends.
Here is the logic in my Server.R file concerning the output of one of dataTables:
dataset_HL <- reactive({
switch(input$dataset_HL,
"Deltas" = DELTA$HL,
"Date 1" = DATE1$HL,
"Date 2" = DATE2$HL)
})
termGroup_HL <- reactive({
switch(input$termGroup_HL,
"ALL" = rowIndex$ALL,
"BOM" = rowIndex$BOM,
"QTR" = rowIndex$QTR,
"CAL" = rowIndex$CAL)
})
values_HL <- reactive({
data <- dataset_HL()
colnames(data) <- locations$HL
data <- cbind(Terms = rownames(data), data)
rows <- termGroup_HL()
return(data[rows, ])
})
output$table_HL <- renderDataTable({
datatable(values_HL(),
rownames = FALSE,
options = list(
pageLength = 25,
lengthMenu = c(10, 25, 50, 100)
))
})
Thank you ahead of time.

I found my answer finally and of course it was already answered by Joe Cheng here, Shiny Reactivity.
Simply adding a call to my action button, input$GET_Dates, inside my reactive function triggered the re-calc of the table.
I also simplified my reactive values function.
values_HL <- reactive({
input$GET_Dates
dataset <- switch(input$dataset_HL,
"Deltas" = DELTA$HL,
"Date 1" = DATE1$HL,
"Date 2" = DATE2$HL)
termGroup <- switch(input$termGroup_HL,
"ALL" = rowIndex$ALL,
"BOM" = rowIndex$BOM,
"QTR" = rowIndex$QTR,
"CAL" = rowIndex$CAL)
data <- dataset[termGroup, ]
data <- cbind(Terms = rownames(data), data)
data
})
output$table_HL <- renderDataTable({
datatable(values_HL(),
rownames = FALSE,
options = list(
pageLength = 25,
lengthMenu = c(10, 25, 50, 100)
))
})

Related

How to edit a DT column and save the changes to trigger calculations in dependent columns?

I'm creating a shiny app that will be used by multiple people to see and edit data in a table format. I want the user to be able to edit one or more columns at a time. I've been using the DT package in R to do this, but I can't figure out how to save the edits made in the data table. This is crucial because there are dependant values in other columns that need to be recalculated.
If I set editable = TRUE I can change the value in one cell, but that is much too slow. When I set editable = "column" or "all" I can edit multiple cells quickly, but then the edits won't save, no matter how many times I hit return.
In the example below, all I'm trying to do is print the edited values to the console. If the values appear in the _cell_edit variable then I can use the editData function to save the changes.
I haven't found anything useful on StackOverflow yet, but I did find the following two blog posts helpful.
https://blog.rstudio.com/2018/03/29/dt-0-4/
https://rstudio.github.io/DT/shiny.html
# TEST APP DT
library(DT)
library(shiny)
library(tidyverse)
# Define UI for application that draws a histogram
ui <- fluidPage(
actionButton("save", "Click to Save Changes"),
DTOutput("dt_table")
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
data <-
data.frame(
A = c("Ones", "Twos", "Threes", "Total"),
B = c(1, 2, 3, 6),
C = c(1, 2, 3, 6),
stringsAsFactors = FALSE
) %>% mutate(D = B + C)
live = reactiveValues(df = NULL)
observe({
live$df <- data
})
output$dt_table <- renderDataTable({
datatable(
live$df,
rownames = FALSE,
editable = list(
target = "column",
disable = list(columns = c(1, 3))
)
)
})
proxy_dt_table <- dataTableProxy("dt_table")
observeEvent(input$save, {
info = input$dt_table_cell_edit
str(info)
row = info$row
col = info$col
val = info$value
print(paste0("Row: ", row))
print(paste0("Col: ", col))
print(paste0("Val: ", val))
})
}
# Run the application
shinyApp(ui = ui, server = server)
Right now, the values in the _cell_edit variable are empty.
NULL
[1] "Row: "
[1] "Col: "
[1] "Val: "
I would like to see something like this:
'data.frame': 200 obs. of 3 variables
[1] "Row: [1, 2, 3, 4, ...]"
[1] "Col: [1, 1, 1, 1, ...]"
[1] "Val: [5, 6, 7, 8, ...]"

Adding groupcheckboxinput values to data frame in Shiny

I am attempting to add the values from a checkboxgroupinput value to the data frame called surv_data in a Shiny App.
Below is the code for the check boxes:
checkboxGroupInput(inputId = "variables", label = "",
choices = c(
"Covariate 1" = "cov1",
"Covariate 2" = "cov2"
),
selected = c('cov1', 'cov2'))
Here is where I combine the variables in to one data frame:
surv_data <- reactive({
raw_surv <- raw_surv_data()
data.frame(
Time = raw_surv[[input$Time]],
Treatment = raw_surv[[input$Treatment]],
endpoint = raw_surv[[input$Endpoint]]
)
})
I need to somehow add the values cov1 and cov2 below the following line:
endpoint = raw_surv[[input$Endpoint]]
I've attempted to add variables = raw_surv[[input$variables]] but unfortunately this does not work. Any help would be appreciated.
Maybe
surv_data <- reactive({
raw_surv <- raw_surv_data()
cbind(
data.frame(
Time = raw_surv[[input$Time]],
Treatment = raw_surv[[input$Treatment]],
endpoint = raw_surv[[input$Endpoint]]
),
raw_surv[input$variables]
)
})

R - Group by Date then Sum by unique ID

Here is my code - creating a dashboard that will filter by date. One tab will show our wellness survey data, the other will show post-practice loading data. I am pulling in the first 3 columns from "post.csv" which are Date, Name, Daily. Then I am looking to create and add the next 3 columns with the math.
Where I am first stuck is that I need my Daily_Load to aggregate data for a specific athlete on the given Date. Then I need to create a rolling 7-day sum for each athlete using the Daily load data from the last 7 days (including Date selected). A 28-Day Rolling Sum/4 and 7-Day/28-Rolling is the last piece.
Thanks again for all of the help!
library(shiny)
library(dplyr)
library(lubridate)
library(ggplot2)
library(DT)
library(zoo)
library(tidyr)
library(tidyverse)
library(data.table)
library(RcppRoll)
AM_Wellness <- read.csv("amwell.csv", stringsAsFactors = FALSE)
Post_Practice <- read.csv("post.csv", stringsAsFactors = FALSE)
Post_Data <- Post_Practice[, 1:3]
Daily_Load <- aggregate(Daily~ ., Post_Data, sum)
Acute_Load <- rollsum(Post_Data$Daily, 7, fill = NA, align = "right")
Chronic_Load <- rollsum(Post_Data$Daily, 28, fill = NA, align = "right")/4
Post_Data['Day Load'] <- aggregate(Daily~ ., Post_Data, sum)
Post_Data['7-Day Sum'] <- Acute_Load
Post_Data['28-Day Rolling'] <- Chronic_Load
Post_Data['Ratio'] <- Acute_Load/Chronic_Load
ui <- fluidPage(
titlePanel("Dashboard"),
sidebarLayout(
sidebarPanel(
dateInput('date',
label = "Date",
value = Sys.Date()
),
selectInput("athleteInput", "Athlete",
choices = c("All"))
),
mainPanel(tabsetPanel(type = "tabs",
tabPanel("AM Wellness", tableOutput("amwell")),
tabPanel("Post Practice", tableOutput("post"))
)
)
)
)
server <- function(input, output) {
output$amwell <- renderTable({
datefilter <- subset(AM_Wellness, AM_Wellness$Date == input$date)
}, hover = TRUE, bordered = TRUE, spacing = "xs", align = "c")
output$post <- renderTable({
datefilter <- subset(Post_Data, Post_Data$Date == input$date)
}, hover = TRUE, bordered = TRUE, spacing = "xs", align = "c")
}
shinyApp(ui = ui, server = server)

R DT::datatables formatting multiple columns simultaneously

I wish to implement formatCurrency() and formatPercentage() (both from DT package) across multiple columns simultaneously in a shiny dashboard. I am using shinymaterial for the given example.
I am currently doing the following:
# The packages to load.
required_packages <- c("shiny", "shinymaterial", "DT", "tidyverse")
# This function will load in all the packages needed.
lapply(required_packages, require, character.only = TRUE)
# A table example.
ui <- material_page(
title = "Example table",
tags$h1("Table example"),
material_card(
title = "Table",
material_row(
DT::dataTableOutput("data_table_example")
),
depth = 1
)
)
server <- function(input, output) {
data_table_example_data = tibble(
Person = paste0("Person ", c(1:100)),
`Price $` = rnorm(100, 50000, 500),
`Cost $` = rnorm(100, 30000, 300),
`Probability %` = rnorm(100, 0.6, 0.1),
`Win %` = rnorm(100, 0.5, 0.2)
)
# This will create an output summary table
output$data_table_example = renderDataTable({
result = datatable(data_table_example_data, options = list(pageLength = 100, scrollX = TRUE),
class = 'cell-border stripe compact', rownames = FALSE) %>%
formatCurrency("Price $") %>%
formatCurrency("Cost $") %>%
formatPercentage("Probability %", digits = 1) %>%
formatPercentage("Win %", digits = 1)
})
}
shinyApp(ui = ui, server = server)
However, what I wish to do is, within the renderDataTable() function, to simplify the format functions into fewer lines. For example, implement formatCurrency() in any column with a "$" and formatPercentage() in any column with a "%".
I have done a fair bit of searching for an appropriate but could not find a solution, but I assume I am just missing a fairly simple solution.
Something like:
# This will create an output summary table
output$data_table_example = renderDataTable({
result = datatable(data_table_example_data, options = list(pageLength = 100, scrollX = TRUE),
class = 'cell-border stripe compact', rownames = FALSE) %>%
formatCurrency(grepl("$", colnames()) %>%
formatPercentage(grepl("%", colnames()), digits = 1)
})
A few additional points:
The tibble will actually be a reactive
This example is a very trivial version of a rather more complex table and set of reactives
I do not want to implement the formatting in the reactive part since I find this then messes with the DT sorting function, since it assumes the column is a character string
Any help will be greatly appreciated
Try:
# This will create an output summary table
output$data_table_example = renderDataTable({
result = datatable(data_table_example_data, options = list(pageLength = 100, scrollX = TRUE),
class = 'cell-border stripe compact', rownames = FALSE) %>%
formatCurrency(grepl("$", colnames(data_table_example_data)) %>%
formatPercentage(grepl("%", colnames(data_table_example_data)), digits = 1)
})
It seems you need to be explicit with the data so colnames() doesn't work - you need colnames(data_table_example_data).
I noticed during testing if you use grepl with rownames = TRUE that rownames becomes the first column name which means all the formatting is out by one. grep seems to not have this issue.

Shiny - Web Framework for R › how to use an input switch to conditionally group

asked this on the shiny google group, w no help yet: I'm struggling with how to pass an input switch to dplyr's group_by_ in the code below.
I bolded the two parts of relevant code in the not-so-MRE below (ie, lines 9:11, and 24).
effectively, if the user selects "daily" in the UI, the resultant grouping should be group_by(year = year(my_date), month = month(my_date), day = day(my_date) in line 24, or remove ANY grouping as the data is already daily.
selecting "monthly", should yield group_by(year = year(my_date), month = month(my_date))
"yearly", should yield group_by(year = year(my_date))
I welcome meta-suggestions/ criticism about how my code/ structures are organized.
Thank you
library(shiny)
library(dplyr)
library(lubridate)
ui <- fluidPage(
dateInput("start", label = "start date", value = "2010-01-01"),
dateInput("end", label = "end date", value = "2020-01-01"),
selectInput("grouping_freq", label = "Granularity",
choices = list("daily" = 1,"monthly" = 2, "Yearly" = 3),
selected = 2),
tableOutput("my_table")
)
server <- function(input, output) {
df <- reactive({ data_frame(my_date = seq(input$start, input$end, by = 'day')) }) ## 10 years of daily data
df2 <- reactive({ df() %>% mutate(dummy_data = cumsum(rnorm( nrow( df() ) ))) })
output$my_table <- renderTable({
df2() %>% group_by(year = year(my_date), month = month(my_date)) %>%
summarise(dummy_data = sum(dummy_data), my_date = as.Date(min(my_date)))
})
}
shinyApp(ui = ui, server = server)
You can use the value chosen in selectInput to create a list of formulas that are passed into group_by_, the version of dplyr::group_by that uses standard evaluation.
group_list <- switch(input$grouping_freq,
list(yr=~year(my_date), mn=~month(my_date), dy=~day(my_date)),
list(yr=~year(my_date), mn=~month(my_date))
list(yr=~year(my_date)))
or if you prefer if statements,
group_list <- if (input$grouping_freq == 1) {
list(yr=~year(my_date), mn=~month(my_date), dy=~day(my_date))
} else if (input$grouping_freq == 2) {
list(yr=~year(my_date), mn=~month(my_date))
} else if (input$grouping_freq == 3) {
list(yr=~year(my_date))
} else {
list()
}
and then you can pass group_list into the renderTable expression
output$my_table <- renderTable({
df2() %>%
group_by_(.dots=group_list) %>%
summarise(dummy_data = sum(dummy_data), my_date = as.Date(min(my_date)))
})
I am not sure what you meant by "remove ANY grouping as the data is already daily." but if the data might already be grouped you can use the ungroup function to remove any groups before applying the groupings in group_list.
Edit: Forgot to include ~ in the list elements so that they evaluate correctly.

Resources