Bryan Hanson
2009-Oct-13 20:43 UTC
[R] General means of matching a color specification to an official R color name
Hello List Dwellers: I?ve looked around quite a bit, but don?t quite see an answer that I understand. I?m looking for a way to take any kind of color specification (rgb, hsv, hcl, hex) and match it to the n-nearest R official color names. Clearly it is easy to interconvert different specification schemes and color spaces, but matching to the name seems a bit trickier. Seems like if one has a specification, it could be fuzzy-matched to the list of official R colors expressed in the same specification. Unfortunately, I don?t know much about fuzzy matching. For example, following some examples I found in the archives and the wiki, I wrote this little function to create a table of official R colors and sort it if desired: colorSpecTable <- function(col = colors(), sort = NULL){ require(gplots) rgbcodes <- t(col2rgb(col)) names <- col hex <- col2hex(col) df <- data.frame(name = names, hex.code = hex, rgbcodes) # additional elements for other color spaces could be added if (!identical(sort, NULL)) df <- sort.data.frame(df, by = sort) } Note that sort.data.frame is from the R-wiki and is appended below. Is there a clever way to search a table created by this function, and identify the n-closest colors based upon some reasonable criteria? What I hope for is something like this: colorMatch <- function(hex = NULL, n, plot = HOPEFULLY) { df.rgb <- colorSpecTable(sort = ~red+green+blue) # master table # now search for the n closest matches of hex in df.rgb$hex.code # perhaps hex should be converted into a different color space 1st # eventually would like to display matches side by side w/hex } Thanks as always. Bryan ************* Bryan Hanson Acting Chair Professor of Chemistry & Biochemistry DePauw University, Greencastle IN USA sort.data.frame <- function(x, by){ # Author: Kevin Wright # with some ideas from Andy Liaw # Found in the R Wiki # x: A data.frame # by: A one-sided formula using + for ascending and - for descending # Sorting is left to right in the formula # Useage is: # library(nlme); # data(Oats) # sort(Oats, by= ~nitro-Variety) if(by[[1]] != "~") stop("Argument 'by' must be a one-sided formula.") # Make the formula into character and remove spaces formc <- as.character(by[2]) formc <- gsub(" ", "", formc) # If the first character is not + or -, add + if(!is.element(substring(formc, 1, 1), c("+", "-"))) formc <- paste("+", formc, sep = "") # Extract the variables from the formula vars <- unlist(strsplit(formc, "[\\+\\-]")) vars <- vars[vars != ""] # Remove any extra "" terms # Build a list of arguments to pass to "order" function calllist <- list() pos <- 1 # Position of + or - for(i in 1:length(vars)){ varsign <- substring(formc, pos, pos) pos <- pos + 1 + nchar(vars[i]) if(is.factor(x[, vars[i]])){ if(varsign == "-") { calllist[[i]] <- -rank(x[, vars[i]]) } else { calllist[[i]] <- rank(x[, vars[i]]) } } else { if(varsign == "-") { calllist[[i]] <- -x[, vars[i]] } else { calllist[[i]] <- x[,vars[i]] } } } return(x[do.call("order", calllist), ]) }
Barry Rowlingson
2009-Oct-13 21:12 UTC
[R] General means of matching a color specification to an official R color name
On Tue, Oct 13, 2009 at 9:43 PM, Bryan Hanson <hanson at depauw.edu> wrote:> Hello List Dwellers: > > I?ve looked around quite a bit, but don?t quite see an answer that I > understand. > > I?m looking for a way to take any kind of color specification (rgb, hsv, > hcl, hex) and match it to the n-nearest R official color names. ?Clearly it > is easy to interconvert different specification schemes and color spaces, > but matching to the name seems a bit trickier. ?Seems like if one has a > specification, it could be fuzzy-matched to the list of official R colors > expressed in the same specification. ?Unfortunately, I don?t know much about > fuzzy matching. > > For example, following some examples I found in the archives and the wiki, I > wrote this little function to create a table of official R colors and sort > it if desired: > > colorSpecTable <- function(col = colors(), sort = NULL){ > ? ?require(gplots) > ? ?rgbcodes <- t(col2rgb(col)) > ? ?names <- col > ? ?hex <- col2hex(col) > ? ?df <- data.frame(name = names, hex.code = hex, rgbcodes) > ? # additional elements for other color spaces could be added > ? ?if (!identical(sort, NULL)) df <- sort.data.frame(df, by = sort) > ? ?} > > Note that sort.data.frame is from the R-wiki and is appended below. ?Is > there a clever way to search a table created by this function, and identify > the n-closest colors based upon some reasonable criteria? ?What I hope for > is something like this: > > colorMatch <- function(hex = NULL, n, plot = HOPEFULLY) { > ? ?df.rgb <- colorSpecTable(sort = ~red+green+blue) # master table > ? ?# now search for the n closest matches of hex in df.rgb$hex.code > ? ?# perhaps hex should be converted into a different color space 1st > ? ?# eventually would like to display matches side by side w/hex > ? ?}You just need to define your distance in colour space. Simplest might be a euclidean distance in three-dimensional r,g,b coordinates, something like: nearColour <- function(r,g,b){ ctable = col2rgb(colors()) cdiff = ctable - c(r,g,b) cdist = cdiff[1,]*cdiff[1,]+cdiff[2,]*cdiff[2,]+cdiff[3,]*cdiff[3,] return(colors()[cdist == min(cdist)]) } This gives colour names nearest to r,g,b triples, with possible multiple results: > nearColour(0,0,0) [1] "black" "gray0" "grey0" > nearColour(1,1,1) [1] "black" "gray0" "grey0" > nearColour(255,255,255) [1] "white" "gray100" "grey100" > nearColour(128,0,0) [1] "darkred" "red4" Any good? You could also do it in hsv space, but there's probably enough colours in the colors() vector that it wouldn't make much difference... Barry