字符串离散域的连续色标?

时间:2012-08-31 14:11:39

标签: javascript d3.js heatmap

我正在实施一个热图,其中单元格背景颜色由d3色标决定。有些值是绝对的;它们的值可以是N个不同的任意字符串类型,如[“6TH”,“7TH”,“5TH”,“4TH”]。

给定起始颜色d3.rgb(“蓝色”)和结束颜色d3.rgb(“红色”),如何构建将字符串的离散域映射到连续颜色范围的颜色比例?

我试过

var scale = d3.scale.ordinal()
    .domain(["6TH", "7TH", "5TH", "4TH"])
    .rangeBands( [ d3.rgb("blue"), d3.rgb("red") ] );

显然不起作用。

3 个答案:

答案 0 :(得分:29)

首先,我会考虑使用一种随时可用的Colorbrewer秤;见colorbrewer2.org。这些也可以作为D3的git存储库中的JavaScript和CSS文件使用;见lib/colorbrewer。例如,如果您的域中有四个离散值,并且您想要一个红蓝分歧的比例,您可以说:

var color = d3.scale.ordinal()
    .domain(["6TH", "7TH", "5TH", "4TH"])
    .range(colorbrewer.RdBu[4]);

(在此之前你还需要一个<script src="colorbrewer.js"></script>。)Colorbrewer有各种精心设计的顺序,分歧和分类色标。

如果您坚持使用自己的色标,我强烈建议您在L*a*b* or HCL color space进行插值以获得准确的感知效果。您可以使用d3.interpolateLabd3.interpolateHcl执行此操作。例如,d3.interpolateLab("red", "blue")(.5)会返回红色和蓝色之间的颜色。

要计算序数标度范围的颜色,可以使用插值器,或者您可以找到更方便的临时线性标度。例如:

var categories = ["6TH", "7TH", "5TH", "4TH"];

var color = d3.scale.ordinal()
    .domain(categories)
    .range(d3.range(categories.length).map(d3.scale.linear()
      .domain([0, categories.length - 1])
      .range(["red", "blue"])
      .interpolate(d3.interpolateLab)));

答案 1 :(得分:3)

你有正确的想法,你只需要处理每个R / G / B颜色通道。例如,在vanilla JavaScript中,您可以执行以下操作:

var a = [255, 0, 0], // First color
    b = [0, 0, 255], // Other color
    bands = 5,       // Bands is the length of your domain
    i, 
    delta = [];      // Difference between color in each channel

// Compute difference between each color
for (i = 0; i < 4; i++){
  delta[i] = (a[i] - b[i]) / (bands + 1);
}

// Use that difference to create your bands
for (i = 0; i <= bands + 1; i++){
  var r = Math.round(a[0] - delta[0] * i);
  var g = Math.round(a[1] - delta[1] * i);
  var b = Math.round(a[2] - delta[2] * i);
  console.log("<div style='background-color: #" + dec2hex(r) + dec2hex(g) + dec2hex(b) + "'>Band " + i + "</div>");
}

// A helper function for formatting
function dec2hex(i) {
  return (i+0x100).toString(16).substr(-2).toUpperCase();
}

根据d3 documentation,您可以使用颜色对象的rgb属性提取每个颜色通道:

  

# d3.rgb(color)

     

通过解析指定的颜色字符串构造一个新的RGB颜色。如果color不是字符串,则强制为字符串;因此,此构造函数也可用于创建现有颜色的副本,或强制将d3.hsl颜色转换为RGB。

     

...

     

生成的颜色存储为[0,255]范围内的红色,绿色和蓝色整数通道值。通道可用作返回对象的r,g和b属性。

因此,在上面的示例的顶部,您可以说:

var myColor = d3.rgb("blue"),
    a = [myColor.r, myColor.g, myColor.b],
...

这有帮助吗?

答案 2 :(得分:0)

您可以随时链接序数比例和线性比例。

第一个刻度将根据离散值创建可量化值,第二个刻度将在色标上插入这些值。

这样的事情:

// Your categories
var data = ["6TH", "7TH", "5TH", "4TH"],

  // Define ordinal to linear scale...
  ordinal = d3.scale.ordinal().domain(data).rangePoints([0, 1]),

  // ...and linear to color scale
  linear = d3.scale.linear().domain([0, 1]).range([d3.rgb("blue"), d3.rgb("red")]);

// Now define your artificial 'compound' scale
function scale(d) {
  return linear(ordinal(d));
}

// And then use it on your D3 code
d3.selectAll('div')
  .data(data)
  .enter()
  .append('div')
  .style('background', scale) // <- et voilà ;)
  .text(function(d) {
    return d;
  });
div {
  color: white;
  width: 3em;
  padding: 1em;
  margin: .2em
  text-align: center;
  font-family: Arial, Helvetica, sans-serif;
  font-weight: bold
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>