0

I am trying to create a shiny app with a plotly output.
The plot should have multiple y axes, and update based on the variables selected.
The question is how to combine the shiny reactivity and plotly while using add_lines, as at the moment if I select less variables than add_lines the code does not function

Sample code:

library(shiny)
library(dplyr)
library(plotly)
library(tidyr)

data <- cbind(
  seq(from = 1, to = 30, by = 1),
  sample(seq(from = 100, to = 300, by = 10), size = 30, replace = TRUE),
  sample(seq(from = 1, to = 100, by = 9), size = 30, replace = TRUE),
  sample(seq(from = 50, to = 60, by = 2), size = 30, replace = TRUE),
  sample(seq(from = 100, to = 130, by = 1), size = 30, replace = TRUE)
) %>% 
  as.data.frame()

names(data) <- c("date", "a", "b", "x", "y")

data <- data %>% gather("key", "value", 2:5)

ui <- fluidPage(
  column(
    width = 3,
    selectInput("select", "Select var:", choices = c("a", "b", "x", "y"), selected = c("a", "b", "x"), multiple = TRUE)
  ),
  column(
    width = 9
  ),
  column(
    width = 12,
    plotlyOutput("plot")
  )
)

server <-  function(input, output){

  output$plot <- renderPlotly({
    data <- data %>% filter(key %in% c("date", input$select)) %>% spread(key, value)

    plot_ly(x = ~data$date) %>%
      add_lines(y = ~data[, 2], name = input$select[1], line = list(color = "red")) %>%
      add_lines(y = ~data[, 3], name = input$select[2], line = list(color = "blue"), yaxis = "y2") %>%
      add_lines(y = ~data[, 4], name = input$select[3], line = list(color = "green"), yaxis = "y3") %>%
      layout(
        yaxis = list(
          side = "left"
        ),
        yaxis2 = list(
          side = "left",
          overlaying = "y",
          anchor = "free",
          position = 0.02
        ),
        yaxis3 = list(
          side = "left",
          overlaying = "y",
          anchor = "free",
          position = 0.04
        )
      )
  })
}

shinyApp(ui, server)

2 Answers 2

2

Here is the solution for you:

library(shiny)
library(dplyr)
library(plotly)
library(tidyr)

data <- cbind(
  seq(from = 1, to = 30, by = 1),
  sample(seq(from = 100, to = 300, by = 10), size = 30, replace = TRUE),
  sample(seq(from = 1, to = 100, by = 9), size = 30, replace = TRUE),
  sample(seq(from = 50, to = 60, by = 2), size = 30, replace = TRUE),
  sample(seq(from = 100, to = 130, by = 1), size = 30, replace = TRUE)
) %>% 
  as.data.frame()

names(data) <- c("date", "a", "b", "x", "y")

data <- data %>% gather("key", "value", 2:5)

ui <- fluidPage(
  column(
    width = 3,
    selectInput("select", "Select var:", choices = c("a", "b", "x", "y"), selected = c("a", "b", "x"), multiple = TRUE)
  ),
  column(
    width = 9
  ),
  column(
    width = 12,
    plotlyOutput("plot")
  )
)

server <-  function(input, output){

  output$plot <- renderPlotly({
    data <- data %>% filter(key %in% c("date", input$select)) 

    plot_ly(data, x = ~date, y=~value, color=~key) %>%
      layout(
        yaxis = list(
          side = "left"
        ),
        yaxis2 = list(
          side = "left",
          overlaying = "y",
          anchor = "free",
          position = 0.02
        ),
        yaxis3 = list(
          side = "left",
          overlaying = "y",
          anchor = "free",
          position = 0.04
        )
      )
  })
}

shinyApp(ui, server)

It is very easy, you should not spread your dataset, instead with long format you can setup an argument color= in plotly, which will directly group your data according to set variable:

plot_ly(data, x = ~date, y=~value, color=~key) 
Sign up to request clarification or add additional context in comments.

1 Comment

the issue with this solution is that I still have the plot on the same initial y axis and additional axis are not used. While what I need is different y axis for each line
1

At least of ~6 months ago, my understanding (from plotly support) was that plotly did not concisely handle this sort of conditional plotting. Instead, if you can enumerate all plotting scenarios, you can use something like the following (which does not actually work yet, need to fix other parts of your code), with an else if for each plotting scenario:

output$plot <- renderPlotly({
data <- data %>% filter(key %in% c("date", input$select)) %>% spread(key, value)

if (input$select == c("a", "b", "x")) {
plot_ly(x = ~data$date) %>%
  add_lines(y = ~data[, 2], name = input$select[1], line = list(color = "red")) %>%
  add_lines(y = ~data[, 3], name = input$select[2], line = list(color = "blue"), yaxis = "y2") %>%
  add_lines(y = ~data[, 4], name = input$select[3], line = list(color = "green"), yaxis = "y3") %>%
  layout(
    yaxis = list(
      side = "left"
    ),
    yaxis2 = list(
      side = "left",
      overlaying = "y",
      anchor = "free",
      position = 0.02
    ),
    yaxis3 = list(
      side = "left",
      overlaying = "y",
      anchor = "free",
      position = 0.04
    )
  )
} else if (input$select == c("a", "b")) {
plot_ly(x = ~data$date) %>%
  add_lines(y = ~data[, 2], name = input$select[1], line = list(color = "red")) %>%
  add_lines(y = ~data[, 3], name = input$select[2], line = list(color = "blue"), yaxis = "y2") %>%
  layout(
    yaxis = list(
      side = "left"
    ),
    yaxis2 = list(
      side = "left",
      overlaying = "y",
      anchor = "free",
      position = 0.02
    ),
    yaxis3 = list(
      side = "left",
      overlaying = "y",
      anchor = "free",
      position = 0.04
    )
  )
    }

})

It is not concise, but may work if there are not a huge number of scenarios.

It also appears you're overwriting your data with the filter call; if your data set is not huge you might skip that step and organize your data outside of the plot call. Otherwise you probably need a reactive function outside of the plot call, that gets called from within the plotting functioning, leaving the original data unmodified.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.