Search code examples
rshinybar-chart

Couldn't show my simple bar charts separately on Shiny R dashboardBody


So I'm trying to make a very simple Shiny R dashboard that shows the progress percentage which will be linked to an editable excel file. here's an example data:

| Month    | PERCENTAGE     |
|:---------|:---------------|
| JAN      | 90             |
| FEB      | 78             |
| MAR      | 100            |
| APR      | 99             |
| MAY      | 90             |
| JUN      | 78             |
| JUL      | 100            |
| AUG      | 87             |
| SEP      | 90             |
| OCT      | 78             |
| NOV      | 99             |
| DES      | 100            |

Here's my ui.R code:

library(ggplot2)
library(shiny)
library(tidyverse)
library(shinydashboard)
library(readxl)
library(shinyalert)

# data1 <- read_excel ("Data1.xlsx")

shinydashboard::dashboardPage(skin = "blue",
              dashboardHeader(title = "UPDL PANDAAN"),
              
              #sidebar
              dashboardSidebar(
                sidebarMenu(
                  menuItem("WIG PMK 2020", tabName = "WIGPMK", icon = icon("tachometer-alt")),
                  fluidPage(
                    actionButton("myButton", "About Us")
                  )
                )),
              dashboardBody(
                h1("PROSENTASE MATERI TAHUN 2022"),
                
                actionButton(
                  inputId = "input1",
                  label = 'JAN'),                           
                actionButton(
                  inputId = 'input2',
                  label = 'FEB'),
                actionButton(
                  inputId = 'input3',
                  label = 'MAR'),
                actionButton(
                  inputId = 'input4',
                  label = 'APR'),
                actionButton(
                  inputId = 'input5',
                  label = 'MAY'),
                actionButton(
                  inputId = 'input6',
                  label = 'JUN'),
                actionButton(
                  inputId = 'input7',
                  label = 'JUL'),
                actionButton(
                  inputId = 'input8',
                  label = 'AUG'),
                actionButton(
                  inputId = 'input9',
                  label = 'SEP'),
                actionButton(
                  inputId = 'input10',
                  label = 'OCT'),
                actionButton(
                  inputId = 'input11',
                  label = 'NOV'),
                actionButton(
                  inputId = 'input12',
                  label = 'DES'),
              
                fluidPage(
                  plotOutput('inpoet')
                )
              )
)

And here's my server.R code:

library(ggplot2)
library(shiny)
library(tidyverse)
library(shinydashboard)
library(DT)
library(readxl)
library(shinyalert)

# Data1 <- read_excel("Data1.xlsx")

shinyServer(function(input, output, session) {
  function(input, output, session) {
    observeEvent(input$input1, {
      output$inpoet1 <- renderPlot({
        plotOutput('plot1')
      })
    })
    
    observeEvent(input$input2, {
      output$inpoet <- renderPlot({
        plotOutput('plot2')
      })
    })
    observeEvent(input$input3, {
      output$inpoet <- renderPlot({
        plotOutput('plot3')
      })
    })
    observeEvent(input$input4, {
      output$inpoet <- renderPlot({
        plotOutput('plot4')
      })
    })
    observeEvent(input$input5, {
      output$inpoet <- renderPlot({
        plotOutput('plot5')
      })
    })
    
    observeEvent(input$input6, {
      output$inpoet <- renderPlot({
        plotOutput('plot6')
      })
    })
    observeEvent(input$input7, {
      output$inpoet <- renderPlot({
        plotOutput('plot7')
      })
    })
    observeEvent(input$input8, {
      output$inpoet <- renderPlot({
        plotOutput('plot8')
      })
    })
    
    observeEvent(input$input9, {
      output$inpoet <- renderPlot({
        plotOutput('plot9')
      })
    })
    
    observeEvent(input$input10, {
      output$inpoet <- renderPlot({
        plotOutput('plot10')
      })
    })
    observeEvent(input$input11, {
      output$inpoet <- renderPlot({
        plotOutput('plot11')
      })
    })
    observeEvent(input$input12, {
      output$inpoet <- renderPlot({
        plotOutput('plot12')
      })
    })
    
    output$plot1 <- renderPlot({
      df <- data.frame(Month=c("JAN"),
                       Percentage=c(90))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot2 <- renderPlot({
      df <- data.frame(Month=c("FEB"),
                       Percentage=c(78))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot3 <- renderPlot({
      df <- data.frame(Month=c("MAR"),
                       Percentage=c(100))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot4 <- renderPlot({
      df <- data.frame(Month=c("APR"),
                       Percentage=c(99))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot5 <- renderPlot({
      df <- data.frame(Month=c("MAY"),
                       Percentage=c(90))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot6 <- renderPlot({
      df <- data.frame(Month=c("JUN"),
                       Percentage=c(78))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot7 <- renderPlot({
      df <- data.frame(Month=c("JUL"),
                       Percentage=c(100))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot8 <- renderPlot({
      df <- data.frame(Month=c("AUG"),
                       Percentage=c(87))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot9 <- renderPlot({
      df <- data.frame(Month=c("SEP"),
                       Percentage=c(90))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot10 <- renderPlot({
      df <- data.frame(Month=c("OCT"),
                       Percentage=c(78))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot11 <- renderPlot({
      df <- data.frame(Month=c("NOV"),
                       Percentage=c(100))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
    
    output$plot12 <- renderPlot({
      df <- data.frame(Month=c("DES"),
                       Percentage=c(100))
      head(df)
      p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
        geom_bar(stat="identity")+
        theme_minimal()
      p<-p + theme(legend.position="none")
      p
      p + coord_flip()
    })
  }
  

  observeEvent(input$myButton, {
    shinyalert(title = "UPDL PANDAAN", imageUrl ="https://lms.pln-pusdiklat.co.id/assets/themes/rti/frontend/img/logo-pln.png", imageWidth = "50%", imageHeight = "50%") }
  )

I'm a beginner at this.


Solution

  • Indeed, it looks like you are trying to do relatively simple app (however it's OK to define complexity based on developer's experience I think).

    I will show you how to make this simpler and how to make it works:

    library(ggplot2)
    library(shiny)
    library(tidyverse)
    library(shinydashboard)
    library(readxl)
    library(shinyalert)
    
    data1 <- data.frame(
      stringsAsFactors = FALSE,
                         Month = c("JAN","FEB",
                                   "MAR","APR","MAY","JUN","JUL","AUG","SEP",
                                   "OCT","NOV","DES"),
                         Percentage = c(90L,78L,100L,
                                   99L,90L,78L,100L,87L,90L,78L,99L,100L)
            )
    
    ui <- shinydashboard::dashboardPage(skin = "blue",
                                        dashboardHeader(title = "UPDL PANDAAN"),
                                        
                                        #sidebar
                                        dashboardSidebar(
                                          sidebarMenu(
                                            menuItem("WIG PMK 2020", tabName = "WIGPMK", icon = icon("tachometer-alt")),
                                            fluidPage(
                                              actionButton("myButton", "About Us")
                                            )
                                          )),
                                        dashboardBody(
                                          h1("PROSENTASE MATERI TAHUN 2022"),
                                          
                                          selectInput("month", "Choose month", choices = data1$Month),
                                            plotOutput('inpoet')
                                        )
    )
    
    server <- function(input, output, session) {
      output$inpoet <- renderPlot({
        df <- data1 %>% 
          filter(Month == input$month)
        p<-ggplot(data=df, aes(x=Month, y=Percentage, fill=Month)) +
          geom_bar(stat="identity")+
          theme_minimal()
        p<-p + theme(legend.position="none")
        p
        p + coord_flip()
      })
      
      observeEvent(input$myButton, {
        shinyalert(title = "UPDL PANDAAN", imageUrl ="https://lms.pln-pusdiklat.co.id/assets/themes/rti/frontend/img/logo-pln.png", imageWidth = "50%", imageHeight = "50%")
        })
    }
    
    shinyApp(ui, server)
    

    In the app above I have removed actionButtons and used selectInput, so instead of buttons we will have a list. And in the server part I have left only one renderPlot. I have used one file (app.R, so on the bottom is shinyApp(ui, server) - this is needed if we have app in one file).

    Let's take a closer look on all of this:

    1. You need to remember that one plotOutput in ui part needs to be connected with one renderPlot in server part by the common inputId. So, because we have plotOutput('inpoet'), then we need to have output$inpoet. Without this you wouldn't see anything rendered on the screen.
    2. How Shiny knows that - when new Month if chosen - it should display different plot? This is because of this code in renderPlot: filter(Month == input$month). And the most important here is input$month - when you use input$ in server part (and inside reactive context, so inside reactive, eventReactive, observe, observeEvent and any render* function), whenever this input$ changes, then Shiny recomputes the new object (plot, data.frame or others) based on this new, changed value.

    And let's take a closer look on your code:

    1. This solution with actionButtons is bad, but I'm not sure how to explain it. Maybe look at my proposition - it is much less complex than yours. If you prefer to use something more similar to your app - check out the radioButtons from shiny.
    2. You shouldn't nest reactives - this is a good practice to not nest them and it is just not necessary, probably in any scenario it won't be necessary.