How to control line chart colors in plotly when lines are added via shiny::selectInput()

I want to display the life expectancy for various countries over time. The user can choose from multiple shiny::selectInput().

My problem is that the colors for the different countries change with the number of chosen countries. For instance, if only Afghanistan is selected, the line is orange, but if Afghanistan and Albania are chosen, the color for Afghanistan changes to light blue. This is distracting and confusing.

(The only way for me to prevent the confusing color changes was to add an actionButton() together with the use of eventReactive() to delay reactions until a user clicks the action button. However, in this case, the UI is more complex and less intuitive.

suppressWarnings(suppressPackageStartupMessages({
    library(shiny)
    library(bslib)
    library(dplyr)
    library(plotly)
}))

gapminder <- gapminder::gapminder

ui <- page_sidebar(
    titlePanel("Life Expectations (1952-2007)"),
    sidebar = sidebar(
        selectInput(
            inputId = "country",
            label = "Country",
            choices = unique(gapminder$country),
            multiple = TRUE
        )
    ),
    card(plotlyOutput("p"))
)

server <- function(input, output, session) {

    countries <- reactive({
        req(input$country)
        gapminder |>
            select(year, lifeExp, country) |>
            filter(country %in% input$country) |>
            arrange(year) |>
            na.omit() |>
            droplevels()
    })

    output$p <- renderPlotly({
        req(countries())
        plotly::plot_ly(
            data = countries(),
            x = ~year,
            y = ~lifeExp,
            color = ~country,
            colors = RColorBrewer::brewer.pal(12, "Paired"),
            type = 'scatter',
            mode = 'lines+markers',
            marker = list(size = 10)
        )
    })
}

shinyApp(ui, server)
#> 
#> Listening on http://127.0.0.1:6810

Created on 2025-09-06 with reprex v2.1.1

I found similar answered questions in StackOverflow, but they didn't help me:

So my question is:
Is there a way to use a multiple selectInput() function to add countries and to adjust, e.g., to fix the colors for the countries already chosen, regardless of the number of countries selected interactively?

I found a solution myself. (I just noted that there was a comment to my question in StackOverflow by Tim G which provided a similar solution!)

The tricky part for me was that I needed a named color vector, as shown in the second example of Custom Color Scale.

What follows is the repetition of my Gapminder example with four lines added and one line changed.

suppressWarnings(suppressPackageStartupMessages({
    library(shiny)
    library(bslib)
    library(dplyr)
    library(plotly)
}))

gapminder <- gapminder::gapminder

ui <- page_sidebar(
    titlePanel("Life Expectations (1952-2007)"),
    sidebar = sidebar(
        selectInput(
            inputId = "country",
            label = "Country",
            choices = unique(gapminder$country),
            multiple = TRUE
        )
    ),
    card(plotlyOutput("p"))
)

server <- function(input, output, session) {

    pal = RColorBrewer::brewer.pal(12, "Paired")  # added

    countries <- reactive({
        req(input$country)
        gapminder |>
            select(year, lifeExp, country) |>
            filter(country %in% input$country) |>
            arrange(year) |>
            na.omit() |>
            droplevels()
    })

    output$p <- renderPlotly({
        req(countries())
        l <- length(input$country)           # added
        length(pal) <- l                     # added
        pal <- setNames(pal, input$country)  # added
        plotly::plot_ly(
            data = countries(),
            x = ~year,
            y = ~lifeExp,
            color = ~country,
            colors = pal,                     # changed
            type = 'scatter',
            mode = 'lines+markers',
            marker = list(size = 10)
        )
    })
}

shinyApp(ui, server)
#> 
#> Listening on http://127.0.0.1:5510

Created on 2025-09-08 with reprex v2.1.1

1 Like

Here the according SO crosspost can be found.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.