Search code examples
rshinyplotly

Create a plotly line chart with dynamic number of traces based on shiny widget selection


I have the shiny app below in which I select a country from the widget to visualize in the plot. I would like to be able to select and visualize more than one countries and color the line for each one with a different color every time with the relative legend in the side. Now I cant see the legend and also the different countries selected. Note that the real dataset is bigger than this one, so the number of countries will be bigger.

## app.R ##
library(shiny)
library(shinydashboard)
library(plotly)
library(dplyr)
library(htmlwidgets)
library(shinyWidgets)

df<-structure(list(Year = c(1951, 1951, 1951, 1951, 1951, 1951, 1954, 
                            1954, 1955, 1955, 1957, 1957, 1957, 1957, 1957, 1957, 1958, 1958, 
                            1958, 1958, 1958, 1958, 1960, 1960, 1960, 1960, 1960, 1960, 1960, 
                            1960, 1960, 1960, 1961, 1961, 1962, 1962, 1962, 1962, 1962, 1962, 
                            1962, 1962, 1962, 1963, 1963, 1963, 1963, 1963, 1963, 1963), 
                   Country = c("Belgium", "France", "Germany", "Italy", "Luxembourg", 
                               "Netherlands", "Canada", "Portugal", "France", "Tunisia", 
                               "Belgium", "France", "Germany", "Italy", "Luxembourg", "Netherlands", 
                               "Costa Rica", "El Salvador", "EU", "Guatemala", "Honduras", 
                               "Nicaragua", "Chile", "EFTA", "El Salvador", "Guatemala", 
                               "Honduras", "MERCOSUR", "Mexico", "Nicaragua", "Peru", "Portugal", 
                               "EU", "Greece", "Algeria", "Egypt", "Ghana", "Guinea", "Iraq", 
                               "Jordan", "Mali", "Morocco", "Syria", "Benin", "Burkina Faso", 
                               "Burundi", "Cameroon", "Central African Republic", "Chad", 
                               "Congo - Brazzaville"), Scope = c(4, 4, 4, 4, 4, 4, 3, 3, 
                                                                 5, 5, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 3, 4, 6, 3, 
                                                                 3, 3, 4, 4, 1, 4, 6, 6, 6, 2, 6, 2, 2, 4, 4, 2, 2, 4, 2, 
                                                                 2, 2, 2, 2, 2, 2)), class = c("grouped_df", "tbl_df", "tbl", 
                                                                                               "data.frame"), row.names = c(NA, -50L), groups = structure(list(
                                                                                                 Year = c(1951, 1954, 1955, 1957, 1958, 1960, 1961, 1962, 
                                                                                                          1963), .rows = structure(list(1:6, 7:8, 9:10, 11:16, 17:22, 
                                                                                                                                        23:32, 33:34, 35:43, 44:50), ptype = integer(0), class = c("vctrs_list_of", 
                                                                                                                                                                                                   "vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
                                                                                                                                                                                                   ), row.names = c(NA, -9L), .drop = TRUE))


ui <- dashboardPage(title="ScopeDashboard",
                    dashboardHeader(title = span("Scope Dashboard")),
                    
                    dashboardSidebar(
                      selectInput(
                        "cou","Country",choices=c(unique(df$Country)),
                        selected = c(unique(df$Country))[1],
                        multiple = T
                      )
                    ),
                    
                    dashboardBody(
                      plotlyOutput("timetrend")
                      
                    )
)

server <- function(input, output) {
  plot_data <- reactive({
    as.data.frame(
      subset(df, df$Country %in% input$cou)
    ) 
  })
  
  output$timetrend<-renderPlotly({

    fig <- plot_ly(
      data = plot_data(),
      x = ~ Year,
      y = ~ Scope,
      mode = "lines+markers",
      marker = list(
        size = 10,
        color = 'rgba(255, 182, 193, .9)',
        line = list(color = 'rgba(152, 0, 0, .8)',
                    width = 2)
      ),
      text = paste(
        "Year :",
        plot_data()$Year,
        "<br> Count of Scopes :",
        plot_data()$Scope
      ),
      hoverinfo = "text"
    )%>%
      add_trace(
        mode = 'lines+markers') %>% layout(
          title = paste("Count of Scope per country and year",
                        "<br>","-",input$cou,"-"),font=t,
          xaxis = list(
            tickangle=45,
            
            dtick = 2
          ),
          yaxis = list(
            dtick = 1,
            tick0 = 0,
            rangemode = "nonnegative"
            
          )
        )
    
    fig
  })
}

shinyApp(ui, server)   

Solution

  • You have to use a reactive value for your plot data and pass the country as color to the plotly function. Note, don't use "df" as variable name as you will run into namespace problems

    server <- function(input, output) {
      # use reactive value for data frame
      plot_data <- reactive({
        as.data.frame(
          subset(df, df$Country %in% input$cou)
        ) 
      })
      
      output$timetrend<-renderPlotly({
        
        fig <- plot_ly(
          data = plot_data(),
          x = ~ Year,
          y = ~ Scope,
          color = ~Country, # <-------------------- Color according to selected Country
          mode = "lines+markers",
          marker = list(
            size = 10       # <------------------- Remove the color argument 
          ), [...]
    

    Will produce this output enter image description here