Reputation: 2930
Despite both sharing the same reactive data frame, why does the bar plot not match the data shown in the table in my shiny app?
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!
# 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 #
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
Reputation: 2930
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
.
# 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
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
Upvotes: 1