1
votes

I am building an app that allows the user to upload a data file and then analyse the data using a standard method. The analysis is dependent on one user input parameter which is populated after the file is uploaded.

The process is:

  1. User uploads .csv file.
  2. uiOutput() is populated with the unique levels in a variable of the uploaded data.
  3. User selects one option in the uiOutput()
  4. User clicks 'Run analysis'.
  5. Table is shown with results.
  6. User can download the analysis results table as a .csv.

Step 4 of the analysis should filter the data by the input from step 3.

I used renderUI in the server function to make the choices based on unique names (levels) in a variable of the file uploaded by the user. Instead of selectInput() in the ui, I have used uiOutput, based on previous answers on SO. This allows the input to be populated based on the uploaded data. But this is actually an output of a renderUI. I would like this option to filter the data, but I don't know how to specify this filtering condition.

The code chunk of interest is #### run analysis based on user input ####

library(shiny)
library(shinythemes)
library(shinyWidgets)
library(dplyr)
library(DT)
library(shinyjs)
library(dplyr)
library(tidyr)
library(stringr)


data_example <- structure( # save as .csv and upload to app
    list(
        site = c("A", "A", "A"),
        analyte = c("x", "y",
                    "z"),
        QA = c(4L, 6L, 3L),
        A1 = c(2L, 6L, 5L),
        A2 = c(1L, 8L,
               4L),
        A3 = c(8L, 32L, 12L)
    ),
    class = "data.frame",
    row.names = c(NA,-3L)
)

#### Define UI for data upload app ####
ui <- fluidPage(theme = shinytheme("flatly"),
                # set the theme aesthetic

                # App title ----
                tags$h3("demo"),
                # Sidebar layout with input and output definitions ----
                sidebarLayout(
                    sidebarPanel(
                        width = 3,
                        #### conditional panel for surface water QA ######
                        conditionalPanel(
                            condition = "input.conditionedPanels == 1",
                            tags$h4("Load data"),
                            tags$hr(style = "border-color: black;"),
                            fileInput(
                                "file1",
                                "Import file",
                                multiple = FALSE,
                                accept = c("text/csv",
                                           "text/comma-separated-values,text/plain",
                                           ".csv")
                            ),

                            checkboxInput("header", "The dataset has column names", TRUE),
                            radioButtons(
                                "sep",
                                "How are the columns seperated?*",
                                choices = c(
                                    Comma = ",",
                                    Semicolon = ";",
                                    Tab = "\t"
                                ),
                                selected = ",",
                                inline = TRUE
                            ),
                            tags$hr(style = "border-color: black;"),
                            tags$h4("Analysis options"),
                            checkboxInput("show_sw", label = "Show  data", value = TRUE),
                            uiOutput("select_qa_site"),

                            actionButton("run_qa", "Run analysis"),
                            downloadButton("download_qa_sw_table", "Download results")
                        )

                    ),

                    #### Main panel (tabs) for displaying outputs ####
                    mainPanel(
                        useShinyjs(),
                        tabsetPanel(
                            type = "tabs",
                            tabPanel(
                                "QA",
                                br(),
                                tags$h4("Raw data view"),
                                tags$hr(style = "border-color: black;"),
                                dataTableOutput("sw_table"),
                                br(),
                                tags$h4("Analysis view"),
                                tags$hr(style = "border-color: black;"),
                                dataTableOutput("sw_qa_results_table"),
                                value = 1
                            ),
                            id = "conditionedPanels"
                        )

                    )

                ))

server <- function(input, output) {
    #### data input for surface water ####
    data_input <- reactive({
        read.csv(input$file1$datapath,
                 header = input$header,
                 sep = input$sep)
    })

    #### sample site names to choose from and run QA analysis ####
    sw_site_names <- reactive({
        req(input$file1)
        names_sw_data <- colnames(data_input())
        names_sw_data[!(colnames(data_input()) %in% c("site",
                                                      "analyte",
                                                      "QA"))]
    })

    output$select_qa_site <- renderUI({
        # Selecting site names based on variable in uploaded data
        selectInput(
            "Select_site",
            label = h4("Select QA sample site"),
            choices = sw_site_names(),
            selected = NULL
        )
    })


    #### produce data table for raw data inspection  ####
    output$sw_table <- renderDataTable({
        req(input$file1)
        datatable(
            data_input(),
            rownames = FALSE,
            options = list(autoWidth = TRUE, scrollX = TRUE)
        )
    })


    #### show/hide raw data table ####
    observeEvent(input$show_sw, {
        if (input$show_sw)
            show("sw_table")
        else
            hide("sw_table")
    })

    #### run analysis based on user input ####
    qa_table <- eventReactive(input$run_qa, {
        data_input() %>%
            gather(sample_location,
                   value,-c(site, analyte, QA)) %>%
            mutate(
                absolute_diff = abs(value - QA),
                value_mean = (value + QA) / 2,
                RPD = round((absolute_diff / value) * 100, 2)
            ) %>%
            filter() # I would like to filter this data based on input from user #
    })

    #### render results of QA analysis to a table for inspection before downloading ####
    output$sw_qa_results_table <- renderDataTable({
        req(input$file1)
        datatable(
            qa_table(),
            rownames = FALSE,
            options = list(autoWidth = FALSE, scrollX = TRUE)
        )
    })

}

##### Create Shiny app ####
shinyApp(ui, server)

I could be just over-engineering the code too, so I'm happy for suggestions that achieve the same outcome but use a different approach.

I have searched for a solution on SO and do not think this is a duplicate question but I'm happy to be directed to a solution if it exists already.

Any help is appreciated.

1
Welcome to stackoverflow. Please add your library calls to the top of your code sample. Otherwise users are guessing which packages you are using.Simon.S.A.
@Simon.S.A. Sorry about that. Added to the top of code.Neil French Collier

1 Answers

0
votes

I believe you want to filter by sample_location?

You can do this by having filter(sample_location == input$Select_site)

So your qa_table will be:

  #### run analysis based on user input ####
  qa_table <- eventReactive(input$run_qa, {
    data_input() %>%
      gather(sample_location,
             value,-c(site, analyte, QA)) %>%
      mutate(
        absolute_diff = abs(value - QA),
        value_mean = (value + QA) / 2,
        RPD = round((absolute_diff / value) * 100, 2)
      ) %>%
      filter(sample_location == input$Select_site) 
  })