andy
andy

Reputation: 2077

Implement Search Function in Shiny Dashboard on multiple plots

Below is the shiny Dashboard. There is a hypothetical Dataframe called SalesDF. It has columns city, SalesCount, Qualifications and Age.

The city column has observations as upper case. That is "NAIROBI", "MOMBASA", "MOMBASA","MOMBASA","NAIROBI".

I want my shinydashboard to re-populate the plots based on searching by city. If a user searches using either "Nairobi", or "NAIROBI", or "NaIROBI", it loads the two charts based on that search function. Finally, if the city is not present, it should return an error such as "City not found".

How do I go about that?

Code to the shinyDashboard

# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(easypackages)
libraries("shiny","shinydashboard","tidyverse","lubridate", "plotly","Rcpp")
theme_set(theme_minimal())

# DF
city <- c("NAIROBI", "MOMBASA", "MOMBASA","MOMBASA","NAIROBI")
SalesCount <- c(34, 50, 23, 70, 33)
Qualifications <- c("More than one", "One","One", "More than one","One")
Age <- c(45, 50, 43, 44, 60)
SalesDF <- data.frame(city, SalesCount, Qualifications, Age)
city <- SalesDF$city

cityCountplot <- ggplot(SalesDF, aes(city, SalesCount)) + 
    geom_col()
cityCountplot


qualifyCountplot <- ggplot(SalesDF, aes(Qualifications, SalesCount)) + 
    geom_col()
qualifyCountplot



library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    titlePanel("Sales Data"),

    # Sidebar with a slider input for number of bins 
    sidebarLayout(
        sidebarPanel(
            # sliderInput("bins",
            #             "Number of bins:",
            #             min = 1,
            #             max = 50,
            #             value = 30)
            sidebarMenu(
                sidebarSearchForm(textId = "Search", buttonId = "searchTown",
                                  label = "Search Town")
            )
        ),

        # Show a plot of the generated distribution
        mainPanel(
           tabsetPanel(
               tabPanel("plot1", plotOutput("plot1")),
               tabPanel("plot2", plotOutput("plot2"))
           )
        )
    )
)

# Define server logic required to draw a histogram
server <- function(input, output) {

   #plot1Output
    output$plot1 <- renderPlot({
        cityCountplot

    })
    
    #plot2Output
    output$plot2 <- renderPlot({
        qualifyCountplot

    })
    
}

# Run the application 
shinyApp(ui = ui, server = server)

Upvotes: 0

Views: 494

Answers (1)

Andrew Chisholm
Andrew Chisholm

Reputation: 6567

Here's some code that implements the required reactive expression and uses toupper to force the user input to upper case. It also displays a message if no city has been found. This is done using the shiny::validate function. Edited to include showing the full graph if the user selects nothing.

library(tidyverse)
library(shiny)
library(shinydashboard)
library(lubridate)

theme_set(theme_minimal())

city <- c("NAIROBI", "MOMBASA", "MOMBASA","MOMBASA","NAIROBI")
SalesCount <- c(34, 50, 23, 70, 33)
Qualifications <- c("More than one", "One","One", "More than one","One")
Age <- c(45, 50, 43, 44, 60)
SalesDF <- data.frame(city, SalesCount, Qualifications, Age)
city <- SalesDF$city

cityCountplot <- ggplot(SalesDF, aes(city, SalesCount)) + geom_col()
cityCountplot

qualifyCountplot <- ggplot(SalesDF, aes(Qualifications, SalesCount)) + geom_col()
qualifyCountplot

ui <- fluidPage(
    titlePanel("Sales Data"),
    
    sidebarLayout(
        sidebarPanel(
            sidebarMenu(
                sidebarSearchForm(textId = "Search", buttonId = "searchTown", label = "Search Town")
            )
        ),
        
        mainPanel(
            tabsetPanel(
                tabPanel("plot1", plotOutput("plot1")),
                tabPanel("plot2", plotOutput("plot2"))
            )
        )
    )
)

server <- function(input, output) {
    filteredSales = reactive({         # Make a data frame that changes when the user chooses something
        if (input$Search == '') {        # Force "" to mean all cities
            df = SalesDF
        } 
        else {
            df = SalesDF %>% dplyr::filter(city == toupper(input$Search))
        }
        df
    })
    
    filteredCityCountPlot = reactive({ # Make a count plot based on the filtered data frame
        df = filteredSales()
        ggplot(df, aes(city, SalesCount)) + geom_col()
    })
    
    filteredQualifyCountPlot = reactive({ # Make a qualification plot based on the filtered data frame
        df = filteredSales()
        ggplot(df, aes(Qualifications, SalesCount)) + geom_col()
    })
    
    output$plot1 <- renderPlot({  # render the count plot with an error if there is no data
        validate(
            need(nrow(filteredSales()) > 0, 'Please select a city')
        )
        filteredCityCountPlot()
    })
    
    output$plot2 <- renderPlot({  # render the qualification plot with an error if there is no data
        validate(
            need(nrow(filteredSales()) > 0, 'Please select a city')
        )
        filteredQualifyCountPlot()
    })
}

shinyApp(ui = ui, server = server)

Upvotes: 1

Related Questions