Search code examples
rsequentialcolor-palette

Sequential palettes for data stored in a list


Hopefully someone here will be able to give me a hint. I have a customized function, which plots the curves from the data stored in different list's elements. I have more than one curve in each element of the list. To each of those curves is related a numeric value, for instance going from 0.1 to 2. So basically I also have a list where each element contains the numeric values related to the curves in that element. I need to plot those curves with a different color, darker for the ones corresponding to the small values and lighter for the ones corresponding to higher values, regardless to which list element they belong. What I need in my function is a list from which I can choose the color for each of the curves. So, for instance, I have a list a: a=list(c(1,2,3),c(8,4,1)).

How can I build a color Palette and assign it the same list structure, such that to 1 corresponds a dark color, to 2 a lighter color, to 8 the lightest color and so on? The important difference here is that in the "a" there are only 5 different values, while in the real case there are 88 different continuous values raging from 1 to 13. I can normalize them so they are between 0 and 1 but still those are 88 different colors/shades of the colors. I was going through the similar topics here but could find anything which would help me to make any progress on this issue. Thank you in advance.


Solution

  • We can use scales::col_numeric here. It takes a vector of colors and the numeric domain over which you wish to apply them, and returns interpolated colors for a given numeric input value. We can write a function that applies this to your list, by getting the minimum and maximum numbers in your list as the domain, then doing an lapply with scales::col_numeric

    make_colors <- function(my_list, low = 'red4', high = 'pink') {
    
      lowest  <- min(unlist(my_list))
      highest <- max(unlist(my_list))
      
      lapply(my_list, function(x) {
        scales::col_numeric(c(low, high), c(lowest, highest))(x)
      })
    } 
    

    Let's try this on your own example.

    a <- list(c(1,2,3), c(8,4,1))
    
    make_colors(a)
    #> [[1]]
    #> [1] "#8B0000" "#9E2A1D" "#B14538"
    #> 
    #> [[2]]
    #> [1] "#FFC0CB" "#C25D53" "#8B0000"
    

    Note that the structure of the output is the same as the structure of the input, with each element in each vector of the original list having a color assigned to it based on its value.

    We can see how these colors look by plotting them. Since we are using the numbers in the list a both for the y position and the color, we should that the lightness of each point is determined by how high it is.

    plot(unlist(a), cex = 3, pch = 16, col = unlist(make_colors(a)))
    

    enter image description here

    Of course, you are free to change the colors of the lowest and highest points to whichever you feel most appropriate.