D3:将两个颜色比例尺合并为一个

5

我目前有两个变量,可以分别映射到两个不同颜色的比例尺s1和s2上。s1给出了与我的变量X的值对应的红色阴影(4种可能的颜色)。s2给出了与我的变量Y的值对应的蓝色阴影(也有4种不同的颜色)。

现在我想要得到的是一些东西,它可以使我将这两个变量组合起来,以得到一种唯一的颜色。因此,对于一对(X,Y),我可以在比例尺上得到一种颜色。因此,我可以得到一个由16种可能颜色组成的比例尺。

下面是一张图例,说明了我正在寻找的东西:

enter image description here

我一直在查看在线示例,但无法弄清楚如何实现这一点。


你目前写了什么代码? - i alarmed alien
1个回答

7
您可以很容易地将两个阈值比例组合成一个新的比例函数。该函数的核心可能如下所示:
d3.scaleBivariate = function() {
  function scaleBivariate(value) {
    var r = reds(value[0]);
    var b = blues(value[1]);

    return "rgb("+r+","+((r+b)/2)+","+b+")";
  }

  var blues = d3.scaleThreshold()
    .range([255,205,155,105,55])
    .domain([0,1,2,3,4,5]);

  var reds = d3.scaleThreshold()
    .range([255,205,155,105,55])
    .domain([0,1,2,3,4,5]);

  return scaleBivariate;

}

这个代码使用了两个d3阈值比例尺来设置红色和蓝色通道。绿色通道是通过这两个通道的平均数来设定的,不过你也可以将其设为任何你想要的值,如0或两个通道中的最小值。我的红/蓝色范围是任意的,也可以轻松更改。

以上代码可以用作:

d3.scaleBivariate = function() {
  function scaleBivariate(value) {
    var r = reds(value[0]);
    var b = blues(value[1]);

    return "rgb("+r+","+((r+b)/2)+","+b+")";
  }

  var blues = d3.scaleThreshold()
    .range([255,205,155,105,55])
    .domain([0,1,2,3,4,5]);
        
  var reds = d3.scaleThreshold()
    .range([255,205,155,105,55])
    .domain([0,1,2,3,4,5]);
        
  return scaleBivariate;

}

// Dummy data:
var data = d3.range(16).map(function(d) {
  return {x: d%4, y: Math.floor(d/4) }
})


var svg = d3.select("svg");
var size = 30;

var color = d3.scaleBivariate();

svg.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("x", function(d) { return d.x * size })
  .attr("y", function(d) { return d.y * size })
  .attr("width",size)
  .attr("height",size)
  .attr("fill",function(d) {
    return color([d.x,d.y]);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.min.js"></script>

<svg></svg>

当然,您可能希望通过添加方法来增加一些灵活性,以修改哪个数据属性设置哪个颜色与哪个属性相关联,阈值应该是什么等等。为了提供一个基本示例,下面的示例已经添加了访问器,用于设置应将哪个属性映射到蓝色和红色通道:

d3.scaleBivariate = function() {

  function scaleBivariate(value) {
     var r = reds(red(value));
     var b = blues(blue(value));
     return "rgb("+r+","+((r+b)/2)+","+b+")";
  }
  
  var blues = d3.scaleThreshold()
    .range([255,205,155,105,55])
    .domain([0,1,2,3,4,5]);
    
  var reds = d3.scaleThreshold()
    .range([255,205,155,105,55])
    .domain([0,1,2,3,4,5]);
    
  var red = function(d) { return d[0]; }
  
  var blue = function(d) { return d[1];}
  
  // Accessors:
  scaleBivariate.red = function(_) {
    return arguments.length ? (red = _, scaleBivariate): red;
  }
  
  scaleBivariate.blue = function(_) {
    return arguments.length ? (blue = _, scaleBivariate): blue;  
  }
  
  return scaleBivariate;
}

var data = d3.range(16).map(function(d) {
  return {x: d%4, y: Math.floor(d/4) }
})

var svg = d3.select("svg");
var size = 30;

// set up the color scale:
var color = d3.scaleBivariate()
  .red(function(d) { return d.x; })
  .blue(function(d) { return d.y; });

svg.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("x", function(d) { return d.x * size })
  .attr("y", function(d) { return d.y * size })
  .attr("width",size)
  .attr("height",size)
  .attr("fill",color);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.min.js"></script>

<svg></svg>


非常好的例子,解释得很清楚。绝对值得点赞。这个代码是否足够灵活,可以使用除颜色以外的其他东西?例如,您如何修改它,使一个变量映射到颜色,另一个变量映射到透明度?或者使用预定义的比例尺,如interpolateViridis? - LBes
换句话说,您将如何修改它以便能够使用1°)透明度比例和d3预定义的比例,例如interpolateViridis? - LBes
1
你应该能够使用斜坡和不透明度,尽管使用.attr("fill".attr("opacity"可能更简单。为了调整答案,您可以基于viridis比例尺指定rgb并使用第二个比例尺指定alpha(使用d3.rgb访问单个颜色)-可能像这样:https://jsfiddle.net/5Lo1afkw/。要拥有一个可以执行斜坡/不透明度或组合单独指定的颜色通道的单一比例尺对象需要一些工作 - 如果使用带颜色纹理,则需要采用不同的方法。 - Andrew Reid
谢谢,这完全回答了我的问题。答案已经被批准。真希望我能再次点赞,非常清晰,代码也很好注释。 - LBes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接