Search code examples
rplotlybar-chartcrosstalk

Why is the standard deviation mismatched in barplot when I am using plotly and crosstalk


I want to produce barplot using plotly and crosstalk, but I found that in the plot, the standard deviations are mismatched.

I don't understand the reason.

Here is my demo data:

library(plotly)
library(crosstalk)
BPData <- data.frame(
  Metabolite = rep(c("X", "Y"), each = 5),
  Group = rep(c("A", "B", "C", "D", "E"), 2),
  MEAN = c(7, 6, 7, 3, 7, 7, 7, 8, 7, 7),
  SD = 1:10
)

> BPData
   Metabolite Group MEAN SD
1           X     A    7  1
2           X     B    6  2
3           X     C    7  3
4           X     D    3  4
5           X     E    7  5
6           Y     A    7  6
7           Y     B    7  7
8           Y     C    8  8
9           Y     D    7  9
10          Y     E    7 10

Below is my minimal example:

BPData <- data.frame(
  Metabolite = rep(c("X", "Y"), each = 5),
  Group = rep(c("A", "B", "C", "D", "E"), 2),
  MEAN = c(7, 6, 7, 3, 7, 7, 7, 8, 7, 7),
  SD = 1:10
)

BPData <- crosstalk::SharedData$new(BPData)
metaboliteFilter <- crosstalk::filter_select(id = "Metabolite", 
                                             label = "Select a metabolite", 
                                             sharedData = BPData, 
                                             group = ~ Metabolite, 
                                             multiple = F
)
BPPlot <- plotly::plot_ly(data = BPData,
                          x = ~ Group,
                          y = ~ MEAN,
                          color = ~ Group,
                          type = 'bar',
                          error_y = ~list(array = SD, color = '#808080')
) %>%
  layout(yaxis = list(categoryorder = "trace"))

filter <- crosstalk::bscols(
  metaboliteFilter, 
  BPPlot
)

crosstalk::bscols(filter)

Solution

  • This is a very strange bug of plotly.

    The error bars appear in the wrong order when grouping data by color.

    So the solution is either to remove the color parameter or to re-order to data by the colored variable before making plot.

    Here is my solution:

    library(plotly)
    library(crosstalk)
    
    BPData <- data.frame(
      Metabolite = rep(c("X", "Y"), each = 5),
      Group = rep(c("A", "B", "C", "D", "E"), 2),
      MEAN = c(7, 6, 7, 3, 7, 7, 7, 8, 7, 7),
      SD = 1:10
    )
    
    # must order data by the colored variable here
    BPData <- BPData[order(BPData$Group),]
    
    BPData <- crosstalk::SharedData$new(BPData)
    metaboliteFilter <- crosstalk::filter_select(id = "Metabolite", 
                                                 label = "Select a metabolite", 
                                                 sharedData = BPData, 
                                                 group = ~ Metabolite, 
                                                 multiple = F
    )
    BPPlot <- plotly::plot_ly(data = BPData,
                              x = ~ Group,
                              y = ~ MEAN,
                              color = ~ Group,
                              error_y = ~list(array = SD, color = '#808080'),
                              type = 'bar'
                              ) %>%
      layout(yaxis = list(categoryorder = "trace"))
    
    filter <- crosstalk::bscols(
      metaboliteFilter, 
      BPPlot
    )
    
    crosstalk::bscols(filter)