Cristian E. Nuno
Cristian E. Nuno

Reputation: 2930

Why isn't bar plot updating based on reactive data frame?

Question

Despite both sharing the same reactive data frame, why does the bar plot not match the data shown in the table in my app?

Overview

I'm currently arranging the iris data frame in df - a reactive expression that uses the input of a radio button and arranges the data based on base::switch(). Afterwards, df is displayed in two forms: a bar plot and a table.

The trouble is that the bar plot doesn't respond to the radio button, while the table does. My desired output would be for the bar plot to be arranged in ascending/descending order - based on the radio button - in the same way the table is arranged.

Any clarification on why this is happening and how I can resolve this would be much appreciated!

Screenshot of App

Code

# load necessary package
library( shiny )
library( tidyverse )

# create UI
ui <- fluidPage(
  title = "Reactive Programming"
  , plotOutput( outputId = "my.barplot" )
  , radioButtons( inputId = "direction"
                  , label = "Arrange the data:"
                  , choices = c("Ascending", "Descending")
                  , selected = "Descending"
                  , inline = TRUE )
  , tableOutput( outputId = "my.table" )
)

# create server
server <- function( input, output, session){

  # arrange iris in ascending/descending order based on the "Sepal.Length" column
  df <- reactive({
    switch( EXPR = input$direction
            , "Ascending" = iris %>% arrange( Sepal.Length ) 
            , "Descending" = iris %>% arrange( desc( Sepal.Length ) ) )
  })

  # plot df()
  output$my.barplot <- renderPlot({
    ggplot( data = df() ) +
      geom_bar( aes( x = Species
                     , y = Sepal.Length )
                , stat = "identity" )
  })

  # show df()
  output$my.table <- renderTable({
    df()
  })
}

# run App
shinyApp( ui = ui, server = server )

# end of script #

Session Info

R version 3.4.4 (2018-03-15)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS High Sierra 10.13.2

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.4/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] forcats_0.3.0   stringr_1.3.0   dplyr_0.7.4     purrr_0.2.4     readr_1.1.1    
 [6] tidyr_0.8.0     tibble_1.4.2    ggplot2_2.2.1   tidyverse_1.2.1 shiny_1.0.5    

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.16     cellranger_1.1.0 pillar_1.2.1     compiler_3.4.4  
 [5] plyr_1.8.4       bindr_0.1.1      tools_3.4.4      digest_0.6.15   
 [9] lubridate_1.7.3  jsonlite_1.5     nlme_3.1-131.1   gtable_0.2.0    
[13] lattice_0.20-35  pkgconfig_2.0.1  rlang_0.2.0      psych_1.7.8     
[17] cli_1.0.0        rstudioapi_0.7   yaml_2.1.18      parallel_3.4.4  
[21] haven_1.1.1      bindrcpp_0.2     xml2_1.2.0       httr_1.3.1      
[25] hms_0.4.2        grid_3.4.4       glue_1.2.0       R6_2.2.2        
[29] readxl_1.0.0     foreign_0.8-69   modelr_0.1.1     reshape2_1.4.3  
[33] magrittr_1.5     scales_0.5.0     htmltools_0.3.6  rvest_0.3.2     
[37] assertthat_0.2.0 mnormt_1.5-5     colorspace_1.3-2 mime_0.5        
[41] xtable_1.8-2     httpuv_1.3.6.2   stringi_1.1.7    lazyeval_0.2.1  
[45] munsell_0.4.3    broom_0.4.3      crayon_1.3.4 

Upvotes: 0

Views: 526

Answers (2)

Cristian E. Nuno
Cristian E. Nuno

Reputation: 2930

Overview

Thanks to @Gregor, I realized my mistake was not understanding that bar plot order is determined by factor level.

While @Vedha Viyash's answer does work, I combined @Gregor's advice to use dplyr::mutate() to alter df()$Species by using stats::reorder() to set the levels in df()$Species to be arranged by df()$Sepal.Length.

This honors the D.R.Y principal by not repeating the construction of the plot object inside of output$my.barplot.

Screenshot of shiny app

# load necessary package
library( shiny )
library( tidyverse )

# create UI
ui <- fluidPage(
  title = "Reactive Programming"
  , plotOutput( outputId = "my.barplot" )
  , radioButtons( inputId = "direction"
                  , label = "Arrange the data:"
                  , choices = c("Ascending", "Descending")
                  , selected = "Descending"
                  , inline = TRUE )
  , tableOutput( outputId = "my.table" )
)

# create server
server <- function( input, output, session){

  # arrange iris in ascending/descending order based on the "Sepal.Length" column
  df <- reactive({
    switch( EXPR = input$direction
            , "Ascending" = iris %>% arrange( Sepal.Length ) %>% mutate( Species = reorder( x = Species, X = Sepal.Length ) )
            , "Descending" = iris %>% arrange( desc( Sepal.Length ) ) %>% mutate( Species = reorder( x = Species, X = desc( Sepal.Length ) ) ) )
  })

  # plot df()
  output$my.barplot <- renderPlot({
    ggplot( data = df() ) +
      geom_bar( aes( x = Species
                     , y = Sepal.Length )
                , stat = "identity" )
  })

  # show df()
  output$my.table <- renderTable({
    df()
  })
}

# run App
shinyApp( ui = ui, server = server )

# end of script #

Upvotes: 0

Vedha Viyash
Vedha Viyash

Reputation: 728

You don't have to change the order of the data in ggplot to change the order in the plot. You have to specify it inside the plot functions:

I've created an if-else condition to create different plots when Ascending or Descending is clicked. Have a look at the code. I've just added a reorder criteria in the geom_bar() function

Code:

library( shiny )
library( tidyverse )

# create UI
ui <- fluidPage(
  title = "Reactive Programming"
  , plotOutput( outputId = "my.barplot" )
  , radioButtons( inputId = "direction"
                  , label = "Arrange the data:"
                  , choices = c("Ascending", "Descending")
                  , selected = "Descending"
                  , inline = TRUE )
  , tableOutput( outputId = "my.table" )
)

# create server
server <- function( input, output, session){

  # arrange iris in ascending/descending order based on the "Sepal.Length" column
  df <- reactive({
    switch( EXPR = input$direction
            , "Ascending" = iris %>% arrange( Sepal.Length ) 
            , "Descending" = iris %>% arrange( desc( Sepal.Length ) ) )
  })

  # plot df()
  output$my.barplot <- renderPlot({
    if(input$direction=="Ascending")
      ggplot( data = df() ) +
      geom_bar( aes( x = Species
                     , y = Sepal.Length )
                , stat = "identity" )
    else if(input$direction=="Descending")
      ggplot( data = df() ) +
      geom_bar( aes( x = reorder(Species,-Sepal.Length)
                     , y = Sepal.Length )
                , stat = "identity" )
  })

  # show df()
  output$my.table <- renderTable({
    df()
  })
}

# run App
shinyApp( ui = ui, server = server )

You can use labs() to rename the axis if you want

The Output shiny app is here Shiny Output

Upvotes: 1

Related Questions