openrndr icon indicating copy to clipboard operation
openrndr copied to clipboard

Implement colorbrewer2 palettes for quick color schemes

Open hamoid opened this issue 5 years ago • 6 comments

Is your feature request related to a problem? While developing one often needs to apply random colors to objects, without yet caring about the specific colors used. Colors need to be different to distinguish shapes from each other. Loading orx-palette and figuring out how to use it may be a distraction at this early stage. Another option might be to use an HSV / HSL color model together with Random.noise0(), but that is somewhat verbose, when compared to something like ColorRGBa.random().

Describe the solution you'd like @edwinRNDR proposed using https://colorbrewer2.org/ which is not actually random but curated color sets. One can choose between 3 modes (sequential, diverging and qualitative) and how many different colors to use (between 3 and 12). For each combination of mode+numberOfColors one obtains a number of color schemes / palettes. Some combination provide more schemes than others.

Additional context 2020-09-01-111308_1039x731_scrot Using the first scheme for qualitative mode with 12 colors

The data for all the color schemes is available at https://github.com/axismaps/colorbrewer/blob/master/colorbrewer_schemes.js under Apache 2.0 license.

hamoid avatar Sep 01 '20 09:09 hamoid

Yes this would be great! Do you imagine this to be part of orx-palette?

edwinRNDR avatar Sep 01 '20 18:09 edwinRNDR

I think it could be in orx-palette files, but I feel it would be nice it would be accessed either via Random. or via ColorRGBa. for easier discovery. What do you think?

hamoid avatar Sep 02 '20 08:09 hamoid

A JavaScript snippet to convert the color schemes to Kotlin:

  1. Evaluate https://github.com/axismaps/colorbrewer/blob/master/colorbrewer_schemes.js in the web browser console (F12)
  2. Run the following JavaScript code in the console:
var result = [];
var types = {};
for(const e in colorbrewer) {
  var type = colorbrewer[e].properties.type;
  if(types[type] === undefined) {
    types[type] = [];
  }
  var palettes = [];
  for(const p in colorbrewer[e]) {
    if(p != "properties") {
      var palette = [];
    	for(const c of colorbrewer[e][p]) {
      	var color = c.match(/\d+/g).map(x => (x / 255.0).toFixed(4)).join(", ");
        palette.push("rgb(" + color + ")");
    	}
      palettes.push("listOf(" + palette.join(", \n") + ")")
    }
  }

	types[type].push("listOf(" + palettes.join(", \n") + ")")
}
for(const t in types) {
  result.push("\"" + t + "\" to listOf(" + types[t] + ")");
}
console.log("val colorbrewer = mapOf(" + result.join(", \n") +")");
  1. Copy the resulting Kotlin code from the console back to the IDE

Having such a long Kotlin code seems to make the IDE quite unresponsive.

  • Is there a way to solve that?
  • Does it make sense to use a map for seq qual and div or should it be a list and referred to as 0, 1 and 2?
  • Do we want to keep the names of the collections? (the current approach just uses lists, getting rid of the name).

hamoid avatar Sep 03 '20 11:09 hamoid

Does this approach go in the same direction as what you're looking for? Ignore the fact that it's glsl if that's an issue.

Also, check out pastel's distinct command which generates as the name implies, distinct color palettes.

ricardomatias avatar Sep 24 '20 15:09 ricardomatias

Thanks for the links. I think glsl-colormap does not provide easily differentiable colors. Maybe pastel's distinct is an algorithmic approach to colorbrewer's manually curated one?

hamoid avatar Sep 24 '20 15:09 hamoid

Updated JS script:

var palettes = [];
var typeNames = {
  'div': 'ColorBrewerType.Diverging',
  'seq': 'ColorBrewerType.Sequential',
  'qual': 'ColorBrewerType.Qualitative'
};
for(const e in colorbrewer) {
  var type = colorbrewer[e].properties.type;
  for(const p in colorbrewer[e]) {
    if(p != "properties") {
      var palette = [];
    	for(const c of colorbrewer[e][p]) {
      	var color = c.match(/\d+/g).map(x => (x / 255.0).toFixed(4)).join(", ");
        palette.push("rgb(" + color + ")");
    	}
      palettes.push("ColorBrewerPalette(\n  listOf(\n    " + palette.join(", \n    ") + "\n  ), " + 
                    typeNames[type] + ")");
    }
  }
}
console.log("val ColorBrewer = listOf(\n" + palettes.join(", \n") +")");

hamoid avatar Jan 24 '24 17:01 hamoid