-2

I attempting to learn RShiny and despite watching several youtube videos and reading documentation there is clearly some fundamental concept of how shiny operates that I am missing and need some help dumbing it down for me. This is also my first ever post so try not to laugh too much!

Main Objective: create an app where a user specifies a date and clicks the actionButton to go grab the stored data file and execute a series of automated data cleaning procedures and end with saving the updated file back to the original folder the file was pulled from. Later I will add a lot more complex tasks but trying to start simple.

Here is an intended example of the date selection

I am not seeing how to upload an excel file attachment so hopefully this works to show the data. basically there 5 initial rows of junk to remove. then various things like renaming values in a column, removing a column, subsetting data, etc.

Junk                                    
that                                    
I                                   
must                                    
remove                                  
Task ID Center  Facility    Money   P   C   S   CC  FC  U
1   C   Bad Name2   1400    2   3   1   2   1   3
2   C   N   1400    2   3   2   4   1   3
3   B   XYZ 2700    2   5   3   3   1   2
4   A   U   150 1   1   1   3   1   1
5   B   XYZ 2000    1   5   5   4   1   4
6   A   U   1500    1   3   1   2   1   3
7   C   D   75  1   1   1   2   1   1
8   B   Ten 60  5   1   4   4   1   1
9   B   XYZ 450 3   2   1   2   1   2
10  B   XYZ 80  2   1   1   1   1   1
11  B   XYZ 65  3   1   1   2   1   2
12  B   Ten 60  2   1   1   2   1   1
13  B   Ten 35  3   1   1   2   1   1
14  C   Bad Name    20  1   1   1   1   1   1

I have two sets of R code to upload the first has the normal R scripts I would run where I manually define date<-"2021-07-15" this code runs fine. I have included in this sample R script various simple examples of types of cleaning I would do.

require(openxlsx)
require(readxl)

# set run date #
date<-c("2021-07-15")

mon<-month.abb[as.numeric(substr(date, 6, 7))]

# set directory #
setwd(paste("C:\\Users\\Desktop\\Test\\",mon,sep=""))


wb<-createWorkbook(paste("testdata",date,sep = " "))
df<-read_excel(paste("testdata ",date,".xlsx",sep=""),sheet = "test", skip = 5)

# Remove FC
df<-df[,-9]

# Fix Names 
df$Facility[df$Facility=="XYZ"]<-"ZYX"
df$Facility[df$Facility=="Bad Name2"]<-"Good Name2"

df$Facility<-as.factor(df$Facility)
df$P<-as.numeric(df$P)

# subset tasks worth less than 1000 #
small<-df[which(df$Money < 1000),]

# data entry check
for(i in 1:nrow(small))
{
  if(small$Money[i]< 100)
  { small$C[i] = 1}
  if(small$Money[i]>= 100 && small$Money[i] < 200)
  { small$C[i] = 2}
}

# subset tasks worth more than 1000
big<-df[which(df$Money >= 1000),]

# create worksheets to save data #
addWorksheet(wb,"small")
addWorksheet(wb,"big")

writeData(wb,"small",small)
writeData(wb,"big",big)

file<-paste("testdata",date,"Edited.xlsx",sep=" ")

saveWorkbook(wb,file,overwrite = TRUE)

Below is my attempt to create an Rshiny app that is probably wrong in a dozen different ways.

require(shiny)
require(readxl)
require(openxlsx)
require(DT)

ui <- fluidPage(
  dateInput("datePull", "Date:", format = "yyyy-mm-dd", value = Sys.Date()),
  actionButton(inputId = "button", label = "Update Date"),
  textOutput("test"),
  dataTableOutput("mytable")
)
  
server <- function(input, output){
  
  # is date even saving correctly? if I run date() in the console I always get something like 
  # "Fri Jul 16 11:13:12 2021"
  # despite specifying a different starting value or a specified format
  date<-eventReactive(input$button, {input$datePull[1]})

  # Everything I have tried to create "mon" without using eventReactive throws an error; 
  # repetitve use of eventReactive to me screams this is the wrong way to do this
  mon<-eventReactive(input$button,{month.abb[as.numeric(substr(date(), 6, 7))]})         
  
  # at this point it is just a repetative problem because any line that calls date() or mon() 
  # errors with a statement along the lines of "this must be reactive..."
  dir<-eventReactive(input$button,{setwd(paste("C:\\Users\\Desktop\\Test\\",mon(),sep=""))})
  
  wb<-eventReactive(input$button,{createWorkbook(paste("testdata",date,sep = " "))})
  df<-eventReactive(input$button,{read_excel(paste("testdata ",date,".xlsx",sep=""),sheet = "test", skip = 5)})
  
  # trying to remove column 
  df<-eventReactive(input$button,{df[,-9]})
          
  output$test <- renderText({paste("Pull mon is ",mon())})

  # Warning: Error in $: object of type 'closure' is not subsettable
  output$mytable = renderDataTable({df()})

}
shinyApp(ui, server)

Appreciate any help explaining how to properly use eventReactive functions and its outputs later on like date()

MrFlick
  • 195,160
  • 17
  • 277
  • 295
Will R
  • 1
  • 1
  • 3
    Welcome to SO! For a start, `eventReactive` doesn't have any "outputs". If you want to use an object whose value depends on some user actions (such as clicking an `actionButton`) you need a `reactive`. Your post contains multiple questions and your code contains many errors. For this reason, I suspect you are not likely to get many responses and may even get close votes for lack of focus. – Limey Jul 16 '21 at 16:16
  • 1
    Welcome, Will. Check this out for some tips on asking [questions](https://stackoverflow.com/help/how-to-ask) – SmokeyShakers Jul 16 '21 at 17:21
  • I will try to keep this follow up more direct. server <- function(input, output){ date<-reactive({input$datePull}) output$test <- renderText({paste("Pull date is ",date())}) so here use reactive but it automatically updates with out waiting for the actionbutton to be selected. Somehow I need to reference the action button inside date<-"...." correct? – Will R Jul 16 '21 at 17:22

1 Answers1

0

Your code is not reproducible since we don't have access to your desktop. Also, with all due respect, I think you have a fundamental misunderstanding of how Shiny (or possibly R itself) works. Please study and understand some online tutorials (the RStudio website is a good place to start) before moving forward.

Here is a MWE that displays a randomly generated dataset that updates if and only if an action button is clicked. I've assumed you want some data displayed immediately, but if you'd rather have a blank GUI until the actionButton is pressed for the first time, that can be done.

As I wrote in my comment, the key is to use reactive(), not eventReactive().

# Use library to load packages, not require
library(shiny)
library(tidyverse)

ui <- fluidPage(
    dateInput("datePull", "Date:", format = "yyyy-mm-dd", value = Sys.Date()),
    actionButton(inputId = "button", label = "Update Date"),
    textOutput("test"),
    dataTableOutput("mytable")
)

server <- function(input, output) {
  # It's bad practice to use a built-in as a variable name, so I have changed the variable name
  selectedDate <- reactive({
      # Introduce a dependency on the actionButton
      input$button
      # Use isolate to ensure that updates occur only when button is clicked
      isolate({ input$datePull[1] })
 })
    
  # Using lubridate would be more robust and result in more intuitive code
  mon <- reactive({
    x <- month.abb[as.numeric(substr(selectedDate(), 6, 7))]
  })         
    
  output$test <- renderText({
    req(mon())
        
    paste("Pull mon is ",mon())
  })
  
  # Only dependency here is on selectedDate, so updates occur only when selectedDate
  # changes.  That is, when the actionButton is clicked
  df <- reactive ({
      # Replace this random data with the contents of your date-dependent CSV.
      tibble(
          SelectedDate= seq(selectedDate(), length.out=10, by=1),
          Value=rnorm(10),
          UnwantedValue=rnorm(10)
      ) %>% 
      select(-UnwantedValue)
  })
  
  output$mytable = renderDataTable({df()})
}

shinyApp(ui = ui, server = server)
Limey
  • 10,234
  • 2
  • 12
  • 32
  • I made the assumption that anyone looking to run the code would swap in their preferred file location. In the future is there a preferred way to load a file or is better to generate example data as you did? I previously tried reactive but not with isolate (I will go back read read up on that more) which is why ended up assuming I needed eventReactive. Can you explain what exactly the difference is between reactive and eventReactive? When is it appropriate to use the latter? oh and thank you! – Will R Jul 19 '21 at 19:09
  • The point is that we don't know what's *in* your files since we can't read them. If the contents aren't critical (as here) random data is fine. If the contents are relevant, post them using `dput()` because then a simple copy-and-paste gives us access. Anything else is less convenient. Use `eventReactive()` for side effects (eg close the app/update GUI). Think of it as function that returns 'NULL`. Use `reactive()` when you need a return value (eg, when the user click the button, load a file and analyse the data - as here). It's a function with a non-NULL return value. – Limey Jul 19 '21 at 19:16