Plot from different datasets upon different inputs using conditional statement

ggplot2
shiny

#1

I have recently started working on shiny, for my school project I am developing a Shiny application that plot the graph using ggplot upon selected inputs.

Now, one of my requirement is that, upon selecting certain inputs in the front-end I have to plot the graph using some ‘X’ dataset. Say I have 3 different datasets, and 4 inputs then,

if(input$A = 1 && input$B = 2 && input$C = 3 && input$D = 4){ 
  //Plot using Dataset1
} 
else if(input$A = 1 && input$B = 2 && input$C = 3 && input$D = 4){ 
  //Plot using Dataset2
}
else if(input$A = 2 && input$B = 3 && input$C = 4 && input$D = 4){ 
  //Plot using Dataset3
}

I figured out that for this sort of logic to work, I need a submit button in the UI page, I’ve checked a couple of examples online, but dint properly understand how to apply it in my case.

Now, when I try to plot the data using the below code, I am getting Error:could not find function "g"
What am I doing wrong here? and how will I be able to plot this information upon Submit button?

I’d appreciate it, if you could please take a look at my code below and help me.

Here’s a sample dataset you can use to reproduce the example -

UI.R

library(shiny)
library("RMySQL")
library(ggplot2)
library(plotly)
# Database Connection and the fetch
dataset <- read.csv("dataset.csv", header=TRUE)
dataset$X <- NULL
dataset$sex <- sub("^$", "Unknown", dataset$sex)

fluidPage(
  fluidRow(
    tags$head(
      tags$style(HTML("
      .shiny-output-error-validation {
        color: #48ca3b;
        font-size: 14pt;
      }
      body {
        -moz-transform: scale(0.9, 0.9); /* Moz-browsers */
        zoom: 0.9; /* Other non-webkit browsers */
        zoom: 90%; /* Webkit browsers */
      }
    "))
    ),
    titlePanel("Define census"),
    
    sidebarPanel(
      
    dateRangeInput('dateRange',
                   label = 'Date Input',
                   start = as.Date("1967-01-01"), end = Sys.Date()),
    
    selectInput("region", label = "Region", 
                choices = c("All",levels(dataset$region)), 
                selected = "ANI"),
   
    selectInput("species", label = "Species", 
                choices = c("All",levels(dataset$species)),
                selected = "ANI"),
    
    selectInput("sex", label = "Sex", 
                choices = unique(dataset$sex), multiple = TRUE, 
                selected = unique(dataset$sex)),
    
    radioButtons(
      "standard_cat_options",
      label="Standard Category",
      choices=list(
        "All",
        "Multiple Select"), selected="All"),
    conditionalPanel(
      condition = "input.standard_cat_options != 'All'",
      selectInput(
        'standard_cat', 
        label = "Select categories", multiple = TRUE, 
        choices=unique(dataset$standard_cat)
      )
    ),
    
    radioButtons(
      "age_cat_options",
      label="Age Category",
      choices=list(
        "All",
        "Multiple Select"), selected="All"),
    conditionalPanel(
      condition = "input.age_cat_options != 'All'",
      selectInput(
        'broad_cat',
        label = "Select age category", multiple = TRUE,
        choices=c("adult", "adjuv", "juv", "pup", "orphan", "W", "YOY", "SA1", "SA2", "SA3", "SA4", "SA5", "SA", "mature", levels(dataset$broad_cat))
      )
    ),
    
    selectInput('x', 'X', names(dataset), names(dataset)[[2]]),
    
    selectInput('y', 'Y', names(dataset), names(dataset)[[8]]),
    
    submitButton("Submit")
    ),
  mainPanel(
    column(12, plotlyOutput("plot1")),
    hr(),
    column(12, plotlyOutput("plot2"))
   )
  )
)

**Server.R**
library(ggplot2)
library("RMySQL")
library("mgcv")
library(plotly)
function(input, output) {
  
# Database Connection and the fetch
  dataset <- read.csv("dataset.csv", header=TRUE)
  
  dataset$X <- NULL
  dataset$sex <- sub("^$", "Unknown", dataset$sex)
  
  # dataset1 <- read.csv("dataset1.csv", header = TRUE, fill = TRUE)
  # dataset2 <- read.csv("dataset2.csv", header = TRUE, fill = TRUE)
  # dataset3 <- read.csv("dataset3.csv", header = TRUE, fill = TRUE)
  
# DataBase disconnected 
# Using the datafram created with name data 
# as in the given data Date is of String type so converted to "Date" type

dataset$date <- as.Date(dataset$date)

#reactive variable initiation for the various inputsinstall.packages('rsconnect')

reactive({
#if(input$region == "ANI" && input$species == "Ej" && input$sex == "Unknown" && input$standard_cat == "All" && input$broad_cat == "YOY"){
if(input$region == "ANI"){
  l <- subset(dataset, region %in% input$region)
  
  k <- subset(l(), date >= as.Date(input$dateRange[1]) & date <= as.Date(input$dateRange[2]))
  
  m <- subset(k(), species %in% input$species)
    
  
  n <- validate(
      need(input$sex, 'No data exists, Please select Gender input')
    )
    subset(m(), sex %in% input$sex)
    
  
  o <- reactive({
      validate(
        need(input$standard_cat, 'No data exists, please select a Standard Category')
        )
      subset(n(), standard_cat %in% input$standard_cat)
    })
  
  g <- reactive({
      validate(
        need(input$broad_cat, 'No data exists, please select an Age Category')
      )
      subset(o(), broad_cat %in% input$broad_cat)
    })
  } 
})

#output plots 

  output$plot1 <- renderPlotly({
    p <- ggplot(g(), aes_string(x=input$x, y=input$y)) + geom_point(alpha=0.4)
    ggplotly(p)
  })
  output$plot2 <- renderPlotly({
    q <- ggplot(g(), aes_string(x=input$x, y=input$y)) + geom_smooth()
    ggplotly(q)
  })
}

Thank you.


#2

Hi @prashu421,

I’d advise coupling an actionButton with an eventReactive function in this instance to create the dataset g you are trying to generate based on the user inputs.

Currently, you a are trying to create the variable g within a reactive({}) function but not actually assigning the result to anything, hence the Error:could not find function "g" message. That would require something like the following… g <- reactive({...}).

But since we want to control the code triggering with a user input, we can use something like g <- eventReactive(input$go, {...}) where go is the id of an action button defined in the UI.

Another issue we need to resolve is the use of an ‘All’ option in you user inputs. User inputs do not know that when ‘All’ is selected, you want to keep all observations of that column, so you have to explicitly tell it to only filter when ‘All’ is not selected. Otherwise it will filter the dataset looking for instances of ‘All’ in the selected column, of which there are none, resulting in an empty dataset.

This can be resolved with with code like:

if (input$region != "All") dataset <- subset(dataset, region %in% region)

I’ve re-written a version of your app as one app.R file using your example dataset and the processes mentioned above. I’m not it’s exactly what you’re looking for but the filtered data will now be fed through to your plotly outputs based on the user inputs. Let me know if you have any questions!

app.R

library(shiny)
library(ggplot2)
library(plotly)

dataset <- read.csv("dataset.csv", header=TRUE)
dataset$X <- NULL
dataset$sex <- sub("^$", "Unknown", dataset$sex)
dataset$date <- as.Date(dataset$date, format = "%m/%d/%Y")

ui <- fluidPage(
  fluidRow(
    tags$head(
      tags$style(HTML("
                      .shiny-output-error-validation {
                      color: #48ca3b;
                      font-size: 14pt;
                      }
                      body {
                      -moz-transform: scale(0.9, 0.9); /* Moz-browsers */
                      zoom: 0.9; /* Other non-webkit browsers */
                      zoom: 90%; /* Webkit browsers */
                      }
                      "))
      ),
    titlePanel("Define census"),
    
    sidebarPanel(
      
      dateRangeInput('dateRange',
                     label = 'Date Input',
                     start = as.Date("1967-01-01"), end = Sys.Date()),
      
      selectInput("region", label = "Region", 
                  choices = c("All",levels(dataset$region)), 
                  selected = "ANI"),
      
      selectInput("species", label = "Species", 
                  choices = c("All",levels(dataset$species)),
                  selected = "All"),
      
      selectInput("sex", label = "Sex", 
                  choices = unique(dataset$sex), multiple = TRUE, 
                  selected = unique(dataset$sex)),
      
      radioButtons(
        "standard_cat_options",
        label="Standard Category",
        choices=list(
          "All",
          "Multiple Select"), selected="All"),
      
      conditionalPanel(
        condition = "input.standard_cat_options != 'All'",
        selectInput(
          'standard_cat', 
          label = "Select categories", multiple = TRUE, 
          choices=unique(dataset$standard_cat)
        )
      ),
      
      radioButtons(
        "age_cat_options",
        label="Age Category",
        choices=list(
          "All",
          "Multiple Select"), selected="All"),
      conditionalPanel(
        condition = "input.age_cat_options != 'All'",
        selectInput(
          'broad_cat',
          label = "Select age category", multiple = TRUE,
          choices=c("adult", "adjuv", "juv", "pup", "orphan", "W", "YOY", "SA1", "SA2", "SA3", "SA4", "SA5", "SA", "mature", levels(dataset$broad_cat))
        )
      ),
      
      selectInput('x', 'X', names(dataset), names(dataset)[[2]]),
      
      selectInput('y', 'Y', names(dataset), names(dataset)[[6]]),
      
      actionButton("go", "Submit")
    ),
    
    mainPanel(
      column(12, plotlyOutput("plot1")),
      hr(),
      column(12, plotlyOutput("plot2"))
      
    )
  )
)

server <- function(input, output) {
  
  g <- eventReactive(input$go, {
    
    if (input$region == "ANI") {
      
      filtered_data <- dataset
      
      if (input$region != "All") filtered_data <- subset(dataset, region %in% input$region)
      
      filtered_data <- subset(filtered_data, date >= as.Date(input$dateRange[1]) & date <= as.Date(input$dateRange[2]))
      
      if (input$species != "All") filtered_data <- subset(filtered_data, species %in% input$species)
      
      validate(
        need(input$sex, 'No data exists, Please select Gender input')
      )
      
      filtered_data <- subset(filtered_data, sex %in% input$sex)
      
      if (input$standard_cat_options != "All") {
        
        validate(
          need(input$standard_cat, 'No data exists, please select a Standard Category')
        )
        
        filtered_data <- subset(filtered_data, standard_cat %in% input$standard_cat)
      }
      
      if (input$age_cat_options != "All") {
      
        validate(
          need(input$broad_cat, 'No data exists, please select an Age Category')
        )
        
        filtered_data <- subset(filtered_data, broad_cat %in% input$broad_cat)
      
      }
      
      return(filtered_data)
      
    }
  })
  
  #output plots 
  
  output$plot1 <- renderPlotly({
    p <- ggplot(g(), aes_string(x=input$x, y=input$y)) + geom_point(alpha=0.4)
    ggplotly(p)
  })
  output$plot2 <- renderPlotly({
    q <- ggplot(g(), aes_string(x=input$x, y=input$y)) + geom_smooth()
    ggplotly(q)
  })
}

shinyApp(ui, server)


#3

Thank you paul, that actually worked without errors, but when I tried to run your app.R including UI and Server, I Wasn’t able to map the data.
But when I divided the code into two different files it worked fine as expected.

Not sure if that’s some buffer issue or what.

But anyways, this resolves my concern to an extent. I am trying to implement my requirements. I appreciate your help.

Thank you very much again.