highcharter icon indicating copy to clipboard operation
highcharter copied to clipboard

Strange reactive update behaviour with div wrapped around highcharter objects

Open MartinGuth opened this issue 7 years ago • 2 comments

Hey Joshua (@jbkunst),

first of all: I really love your package! It makes shiny apps even better! And I would like to thank you for your quick responses here and over at Stackoverflow - saved my developer-life quit a few times now ;-)

However, I've discovered a strange reactive update/render behaviour with the charts when you wrap an object with a div and set the same name for both IDs, the div ID and the highcharter ID. I know, setting the same name for something like an ID isn't really a good idea, but I wasn't thinking about it and thus spent the last days debugging this problem. However, base R objects like barplots or a data tables do not have said problem with the same ID, i.e. they update/render properly.

Here is a small working example wich reproduces the bug. If the user changes the input in the dropdown, both charts should be redrawn. However, sometimes both do not react on the change. Sometimes only the waterfall chart reacts to the changes, but not the barchart:

library(shiny)
library(dplyr)
library(highcharter)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      uiOutput("cars")
    ),
    
    mainPanel(
      tabsetPanel(
        tabPanel("Linechart",
                 div(id = "hc_linechart",
                     highchartOutput("hc_linechart", height = "500px")
                 )
        ),
        tabPanel("Waterfall",
                 div(id = "hc_waterfall",
                     highchartOutput("hc_waterfall", height = "500px")
                 )   
        )
      )
    )
  )
)

server <- function(input, output) {
   
  output$cars <- renderUI({
    selectizeInput(
      inputId = "cars",
      label = NULL,
      choices = rownames(mtcars),
      options = list(placeholder = 'Cars')
    )
  })
  
  output$hc_linechart <- renderHighchart({
    
    data_line <- subset(mtcars, rownames(mtcars) %in% input$cars)
    
    hc <- highchart() %>%
      hc_chart(type = "column") %>%
      hc_title(text = rownames(data_line), useHTML = TRUE) %>%
      hc_yAxis(title = "") %>%
      hc_xAxis(title = "")
    
    for(i in 1:(ncol(data_line)))
    {
      hc <- hc %>%
        hc_add_series(data = data_line[,i], name = names(data_line)[i])
    }
    hc
  })
  
  
  output$hc_waterfall <- renderHighchart({
    data_line <- subset(mtcars, rownames(mtcars) %in% input$cars)
    name <- c(names(data_line),"Sum")
    
    y <- data_line[,1]
    color <- "#377EB8"
    
    for(i in 2:(ncol(data_line)))
    {
      y <- c(y, data_line[,i]-data_line[,i-1])
      
      if(y[i] > 0)
      {
        color <- c(color, "#4DAF4A")
      }else
      {
        color = c(color, "#E41A1C")
      }
    }
    
    y <- c(y, NA)
    color = c(color, "#377EB8")
    
    isIntermediateSum = rep(FALSE, times = 12)
    isSum <- rep(FALSE, times = 11)
    isSum <- c(isSum, TRUE)
    
    dataframe = data.frame(name, y, isIntermediateSum, isSum, color, stringsAsFactors = F)
    
    hc <- highchart() %>%
      hc_chart(type = "waterfall") %>%
      hc_title(text = rownames(data_line), useHTML = TRUE) %>%
      hc_yAxis(title = "") %>%
      hc_xAxis(title = "") %>%
      hc_add_series(data = dataframe, 
                    dataLabels = list(
                      enabled=TRUE,
                      formatter= JS("function(){ return Highcharts.numberFormat(this.y, 2, ',');}"),
                      style=list(
                        color="#FFFFFF",
                        fontWeight="bold",
                        textShadow="0px 0px 3px black"
                      )
                    )
      )
    hc
  })
}

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

If you change the ID of the divs or the highcharter objects, the update mechanism works as expected. Here I change the div IDs to "css_hc_linechart" and "css_hc_waterfall":

        tabPanel("Linechart",
                 div(id = "css_hc_linechart",
                     highchartOutput("hc_linechart", height = "500px")
                 )
        ),
        tabPanel("Waterfall",
                 div(id = "css_hc_waterfall",
                     highchartOutput("hc_waterfall", height = "500px")
                 )     
        )

Now let's take other R objects instead of the highcharter object, but use again the same IDs:

library(shiny)
library(reshape2)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      uiOutput("cars")
    ),
    mainPanel(
      tabsetPanel(
        tabPanel("Linechart",
                 div(id = "hc_linechart",
                     plotOutput("hc_linechart")
                 )
        ),
        tabPanel("Waterfall",
                 div(id = "hc_waterfall",
                     dataTableOutput("hc_waterfall")
                 )      
        )
      )
    )
  )
)

server <- function(input, output) {
   
  output$cars <- renderUI({
    selectizeInput(
      inputId = "cars",
      label = NULL,
      choices = rownames(mtcars),
      options = list(placeholder = 'Cars')
    )
  })
  
  output$hc_waterfall <- renderDataTable({
    data_line <- subset(mtcars, rownames(mtcars) %in% input$cars)
    return(data_line)
  },  options = list(orderClasses = TRUE, pageLength = 20)
  )
  
  output$hc_linechart <- renderPlot({
    data_line <- subset(mtcars, rownames(mtcars) %in% input$cars)
    data_line <- melt(data_line, measure.vars = 1:11)
    barplot(data_line$value,
            main=rownames(data_line),
            ylab="Numbers",
            xlab="Parts"
    )
  })

}

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

As you can see, the chart and the data table update properly when the user changes the input.

Lastly, my session info:

> sessionInfo()
R version 3.3.3 (2017-03-06)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: Red Hat Enterprise Linux

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8   
 [6] LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

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

other attached packages:
 [1] gtools_3.5.0           reshape2_1.4.2         readxl_1.0.0           microbenchmark_1.4-2.1 purrr_0.2.2            feather_0.3.1         
 [7] highcharter_0.5.0      ggplot2_2.2.1          tidyr_0.6.1            dplyr_0.5.0            rintrojs_0.1.2         shinyjs_0.9           
[13] shinyBS_0.61           data.table_1.10.4      htmlTable_1.9          shiny_1.0.3           

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.10     cellranger_1.1.0 plyr_1.8.4       xts_0.9-7        tools_3.3.3      digest_0.6.12    lubridate_1.6.0  jsonlite_1.5    
 [9] tibble_1.3.0     checkmate_1.8.2  gtable_0.2.0     nlme_3.1-131     lattice_0.20-35  igraph_1.0.1     psych_1.7.5      DBI_0.6-1       
[17] yaml_2.1.14      parallel_3.3.3   stringr_1.2.0    knitr_1.15.1     hms_0.3          htmlwidgets_0.9  R6_2.2.2         foreign_0.8-68  
[25] TTR_0.23-1       magrittr_1.5     backports_1.0.5  scales_0.4.1     htmltools_0.3.6  rlist_0.4.6.1    quantmod_0.4-9   assertthat_0.2.0
[33] mnormt_1.5-5     mime_0.5         xtable_1.8-2     colorspace_1.3-2 httpuv_1.3.3     stringi_1.1.5    miniUI_0.1.1     lazyeval_0.2.0  
[41] munsell_0.4.3    broom_0.4.2      zoo_1.8-0     

MartinGuth avatar Jul 24 '17 16:07 MartinGuth

Hey @MartinGuth !

I will take a look on this!

jbkunst avatar Aug 30 '17 17:08 jbkunst

Hello ! I'm facing the same issue, any progress on this ?

chalioui avatar Aug 21 '20 15:08 chalioui