daattali / colourpicker

🎨 A colour picker tool for Shiny and for selecting colours in plots (in R)
https://daattali.com/shiny/colourInput/
Other
215 stars 28 forks source link

returned name is different from allowed colors name #50

Closed gitdemont closed 2 years ago

gitdemont commented 2 years ago

Hi there,

I am facing an error with colourInput I did not get previously. Here is a min reprex

library(shiny)
library(colourpicker)
shinyApp(
  ui = fluidPage(
    strong("Selected colour:", textOutput("value", inline = TRUE)),
    p(),
    strong("cyan 4 in R colors():", "cyan4" %in% colors()),
    p(),
    colourInput(inputId = "col", label = "Choose colour", value = "red",
                allowTransparent = FALSE, allowedCols = c("red", "cyan4", "cyan"),palette = "limited",
                returnName = TRUE),
  ),
  server = function(input, output, session) {
    output$value <- renderText(input$col)
  }
)

Unfortunately I can't track the exact version where it appeared. I also tested that "cyan4" is still part of known for R colors() to double check this does not come from R itself Finally, I tested with a very old v1.0 version (I have on another computer) and this does not happen (i.e. cyan4 selection returns cyan4 and not darkcyan)

I don't know if this can happen with other names. I discovered it with "cyan4"

I am using R v4.1.3, under windows 10 coloupicker v1.1.0 shiny v1.7.1

daattali commented 2 years ago

darkcyan and cyan4 seem to be the exact same colour. You can verify this yourself:

> col2rgb(c("cyan", "cyan4", "darkcyan"))
      [,1] [,2] [,3]
red      0    0    0
green  255  139  139
blue   255  139  139

Based on that information, the current behaviour is correct. There are a few other colours that have duplicate names for the exact same colour, and in any such case there is one canonical name that must be chosen.

There is no direct connection between the name that you pass into the input and the name that gets returned in the output. When a colour is name is provided by the input, it must get converted into a hex code for the javascript widget. Regardless of what version of the colour you pass into the input -- whether it's the hex code, the rgb code, rgba, hsl, canonical name, or synonym name -- they all end up as just a hex code (in this case #008B8B). Then when the javascript widget needs to return the colour name to R, I've manually added all the R colours names+hex codes to allow for the returnName parameter to work. You can see that here https://github.com/daattali/jquery-colourpicker/blob/a87752bcd31e9911006dfd8acb923970016d6e87/js/colourpicker.js#L627

Closing as this is not a bug

gitdemont commented 2 years ago

Thanks @daattali for your reply.

And thanks you also for the pointer which helped me to identify where this behaviour may came from. If I am not mistaking: In v1.0 of colourpicker, colsToNames did contain "cyan4" but not "darkcyan" Whereas, in v1.1.0, colsToNames does contain "darkcyan" but not "cyan4"

Indeed, "cyan4" and "darkcyan" are same colors in R, like others e.g. (col2rgb(c("blue","blue1"))), as confirmed by col2rgb In addition, calling colors(distinct = TRUE) allows to retrieve list of non-duplicated R colors names:

# list of colors not part of colors with `distinct = TRUE`
K = colors(distinct = FALSE)
K[!(K %in% colors(distinct = TRUE))]

Maybe this is linked to some locale settings in my R session, but on my computer "cyan4" is part of colors(distinct = TRUE) whereas "darkcyan" is not.

Finally, you mentioned that there is no direct connection between input and output. In the case of palette = "limited" and returnName = TRUE, it would be great to have such functionality where returned names should be matched against expected names. However, I guess this should work only as long as user did not introduce duplicated colors in allowedCols

daattali commented 2 years ago

Introducing such a link wouldn't make sense, it would involve a lot of code changes for supporting a minute feature. The input itself cannot differentiate between cyan4 and darkcyan. For example, suppose you use updateColourInput to set the colour to "cyan4" and then you use it again to set it to "darkcyan". Thetr would not actually be any update the second time - the colour picker won't notice a difference.