2

I am trying to generate multiple graphs in Plotly for 30 different sales offices. Each graph would have 3 lines: sales, COGS, and inventory. I would like to keep this on one graph with 30 buttons for the different offices. This is the closest solution I could find on SO:

 ## Create random data. cols holds the parameter that should be switched
l <- lapply(1:100, function(i) rnorm(100))
df <- as.data.frame(l)
cols <- paste0(letters, 1:100)
colnames(df) <- cols
df[["c"]] <- 1:100

## Add trace directly here, since plotly adds a blank trace otherwise
p <- plot_ly(df,
      type = "scatter",
      mode = "lines",
      x = ~c, 
      y= ~df[[cols[[1]]]], 
      name = cols[[1]])
## Add arbitrary number of traces
## Ignore first col as it has already been added
for (col in cols[-1]) {
  p <- p %>% add_lines(x = ~c, y = df[[col]], name = col, visible = FALSE)
}

p <- p %>%
    layout(
      title = "Dropdown line plot",
      xaxis = list(title = "x"),
      yaxis = list(title = "y"),
      updatemenus = list(
        list(
            y = 0.7,
            ## Add all buttons at once
            buttons = lapply(cols, function(col) {
              list(method="restyle", 
                args = list("visible", cols == col),
                label = col)
            })
        )
      )
    )

print(p)

It works but only on graphs with single lines/traces. How can I modify this code to do the same thing but with graphs with 2 or more traces? or is there a better solution? Any help would be appreciated!

### EXAMPLE 2

#create fake time series data
library(plotly)
set.seed(1)
df <- data.frame(replicate(31,sample(200:500,24,rep=TRUE)))
cols <- paste0(letters, 1:31)
colnames(df) <- cols


#create time series

timeseries <- ts(df[[1]], start = c(2018,1), end = c(2019,12), frequency = 12)

fit <- auto.arima(timeseries, d=1, D=1, stepwise =FALSE, approximation = FALSE)
fore <- forecast(fit, h = 12, level = c(80, 95))


## Add trace directly here, since plotly adds a blank trace otherwise

p <- plot_ly() %>%
  add_lines(x = time(timeseries), y = timeseries,
            color = I("black"), name = "observed") %>%
  add_ribbons(x = time(fore$mean), ymin = fore$lower[, 2], ymax = fore$upper[, 2],
              color = I("gray95"), name = "95% confidence") %>%
  add_ribbons(x = time(fore$mean), ymin = fore$lower[, 1], ymax = fore$upper[, 1],
              color = I("gray80"), name = "80% confidence") %>%
  add_lines(x = time(fore$mean), y = fore$mean, color = I("blue"), name = "prediction")


## Add arbitrary number of traces
## Ignore first col as it has already been added

for (col in cols[2:31]) {


  timeseries <- ts(df[[col]], start = c(2018,1), end = c(2019,12), frequency = 12)


  fit <- auto.arima(timeseries, d=1, D=1, stepwise =FALSE, approximation = FALSE)
  fore <- forecast(fit, h = 12, level = c(80, 95))

  p <- p %>%
    add_lines(x = time(timeseries), y = timeseries,
              color = I("black"), name = "observed", visible = FALSE) %>%
    add_ribbons(x = time(fore$mean), ymin = fore$lower[, 2], ymax = fore$upper[, 2],
                color = I("gray95"), name = "95% confidence", visible = FALSE) %>%
    add_ribbons(x = time(fore$mean), ymin = fore$lower[, 1], ymax = fore$upper[, 1],
                color = I("gray80"), name = "80% confidence", visible = FALSE) %>%
    add_lines(x = time(fore$mean), y = fore$mean, color = I("blue"), name = "prediction", visible = FALSE)

}

p <- p %>%
  layout(
    title = "Dropdown line plot",
    xaxis = list(title = "x"),
    yaxis = list(title = "y"),
    updatemenus = list(
      list(
        y = 0.7,
        ## Add all buttons at once
        buttons = lapply(cols, function(col) {
          list(method="restyle", 
               args = list("visible", cols == col),
               label = col)
        })
      )
    )
  )
p
snk550
  • 35
  • 6

1 Answers1

1

You were very close! If for example you want graphs with 3 traces, You only need to tweak two things:

  1. Set visible the three first traces,
  2. Modify buttons to show traces in groups of three.

My code:

## Create random data. cols holds the parameter that should be switched
library(plotly)
l <- lapply(1:99, function(i) rnorm(100))
df <- as.data.frame(l)
cols <- paste0(letters, 1:99)
colnames(df) <- cols
df[["c"]] <- 1:100

## Add trace directly here, since plotly adds a blank trace otherwise
p <- plot_ly(df,
             type = "scatter",
             mode = "lines",
             x = ~c, 
             y= ~df[[cols[[1]]]], 
             name = cols[[1]])
p <- p %>% add_lines(x = ~c, y = df[[2]], name =  cols[[2]], visible = T)
p <- p %>% add_lines(x = ~c, y = df[[3]], name =  cols[[3]], visible = T)
## Add arbitrary number of traces
## Ignore first col as it has already been added
for (col in cols[4:99]) {
  print(col)
  p <- p %>% add_lines(x = ~c, y = df[[col]], name = col, visible = F)
}

p <- p %>%
  layout(
    title = "Dropdown line plot",
    xaxis = list(title = "x"),
    yaxis = list(title = "y"),
    updatemenus = list(
      list(
        y = 0.7,
        ## Add all buttons at once
        buttons = lapply(0:32, function(col) {
          list(method="restyle", 
               args = list("visible", cols == c(cols[col*3+1],cols[col*3+2],cols[col*3+3])),
               label = paste0(cols[col*3+1], " ",cols[col*3+2], " ",cols[col*3+3] ))
        })
      )
    )
  )

print(p)

PD: I only use 99 cols because I want 33 groups of 3 graphs

LocoGris
  • 4,432
  • 3
  • 15
  • 30
  • @JohnnyCrunch how about the second example in the original post? It is for time series data and has lines for observed, prediction, and 80 95 percent confidence intervals. I tried applying your solution to the above but the buttons are still offset. – snk550 Mar 01 '19 at 02:52