Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding custom colours to text labels in plotly R

Following on from my previous question here, using the same reprex I am now trying to add custom colours to both bars and label's font colour. The goal is to have white font colour for text labels when the bar has dark fill colour.

Adding bar colours as named vector worked well, but the same method doesn't work for label's font colour. In the image below Month 4 and Month 5 colours are not as intended and different from the other months.

library(dplyr)
library(tibble)
library(plotly)

df <- structure(list(dsc_cat1 = c("Cat1", "Cat1", "Cat2", "Cat1", "Cat1", 
                                  "Cat2", "Cat2", "Cat1", "Cat1", "Cat2", "Cat2", "Cat1", "Cat1", 
                                  "Cat2", "Cat2", "Cat1", "Cat1", "Cat2", "Cat1", "Cat1", "Cat2", 
                                  "Cat2"), dsc_cat3 = c("Var 1", "Var 2", "Var 3", "Var 1", "Var 2", 
                                                        "Var 3", "Var 4", "Var 1", "Var 2", "Var 3", "Var 4", "Var 1", 
                                                        "Var 2", "Var 5", "Var 3", "Var 1", "Var 2", "Var 3", "Var 1", 
                                                        "Var 2", "Var 3", "Var 4"), val = c(6200.63, 5358.48, 2417.35, 
                                                                                            8022.49, 14852.6, 2417.35, 100.93, 5389.56, 14631.52, 2417.35, 
                                                                                            84.39, 5387.66, 18231.84, 632.72, 1325.05, 5387.03, 14852.6, 
                                                                                            2417.35, 5377.88, 14087.98, 1510.02, 47.27), mth = c(1, 1, 1, 
                                                                                                                                                 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6)), row.names = c(NA, 
                                                                                                                                                                                                                          -22L), class = c("tbl_df", "tbl", "data.frame"))

fill_colours <- setNames(
  object = c(
     "#304996"
    ,"#515575"
    ,"#915f78"
    ,"#cd6873"
    ,"#e88c7d"
  )
  ,nm = paste("Var", 1:5)
)

label_colours <- setNames(
  object = c(
     "white"
    ,"white"
    ,"white"
    ,"black"
    ,"black"
  )
  ,nm = paste("Var", 1:5)
)


subplot(
  lapply(unique(df$mth), function(m) {
    
    data <- df %>%  
      mutate(val = ifelse(mth==m, val, 0)) %>%
      arrange(dsc_cat1) 
    
    x_title <- paste("Month", m)  
    show_legend = ifelse(m == 1, TRUE, FALSE)
    
    plot_ly(data = data, 
            x = ~dsc_cat1,
            y = ~val,
            type = "bar",
            legendgroup=~dsc_cat3,
            text = ~val,
            textfont = list(size = 12, color = label_colours),
            textposition = "auto",
            color = ~dsc_cat3,
            colors = fill_colours,
            showlegend=show_legend
    ) %>% 
      layout(xaxis = list(title = x_title))
  }), titleX = TRUE, shareY = TRUE) %>% 
  layout(barmode = 'stack', showlegend = TRUE)

enter image description here

Next I joined the label colours to the original data, so that plotly can read the colours directly from the data. As can be from the image below, the colours for Var 3 should be white but for Month 3 and Month 6 the labels are in black.

df <- df %>% 
  left_join(
    y = enframe(label_colours)
    ,by = c("dsc_cat3" = "name")
  )


subplot(
  lapply(unique(df$mth), function(m) {
    
    data <- df %>%  
      mutate(
        val = ifelse(mth==m, val, 0)
      ) %>%
      arrange(dsc_cat1) 
    
    x_title <- paste("Month", m)  
    show_legend = ifelse(m == 1, TRUE, FALSE)
    
    plot_ly(data = data, 
            x = ~dsc_cat1,
            y = ~val,
            type = "bar",
            legendgroup=~dsc_cat3,
            text = ~val,
            textfont = list(size = 12, color = ~value),
            textposition = "auto",
            color = ~dsc_cat3,
            colors = fill_colours,
            showlegend=show_legend
    ) %>% 
      layout(xaxis = list(title = x_title))
  }), titleX = TRUE, shareY = TRUE) %>% 
  layout(barmode = 'stack', showlegend = TRUE)

enter image description here

Any help is appreciated, TIA.

like image 874
sactyr Avatar asked Oct 20 '25 11:10

sactyr


1 Answers

You have to arrange your data by both cat1 and cat3. I don't 100% understand but I think because the textfont is in a list it is selecting all the values, and using them in the order they are, not lining them up with the data. If you arrange based on both columns that data is sorted on it should select them in the correct order.

See commented line below

subplot(
  lapply(unique(df$mth), function(m) {
  
  data <- df %>%  
    mutate(
      val = ifelse(mth==m, val, 0)
    ) %>%
    #### THIS LINE ONLY CHANGE
    arrange(dsc_cat1, dsc_cat3) 
  
  x_title <- paste("Month", m)  
  show_legend = ifelse(m == 1, TRUE, FALSE)
  
  plot_ly(data = data, 
          x = ~dsc_cat1,
          y = ~val,
          type = "bar",
          legendgroup=~dsc_cat3,
          text = ~val,
          textfont =  ~value,
          textposition = "auto",
          color = ~dsc_cat3,
          colors = fill_colours,
          showlegend=show_legend
  ) %>% 
    layout(xaxis = list(title = x_title))
}), titleX = TRUE, shareY = TRUE) %>% 
layout(barmode = 'stack', showlegend = TRUE)
like image 79
Sarah Avatar answered Oct 22 '25 02:10

Sarah



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!