【问题标题】:D3: Combine two colour scales into oneD3:将两个色标合二为一
【发布时间】:2019-03-20 05:01:06
【问题描述】:

我目前有两个变量,我可以将它们映射到两个色标 s1 和 s2 上的两种不同颜色。 s1 为我提供了与我的变量 X 的值相对应的红色阴影(4 种不同的可能颜色)。 s1 为我提供了与变量 Y 的值相对应的蓝色阴影(也有 4 种不同的可能颜色)。

现在我想得到的是允许我将这两者结合起来以获得变量组合的独特颜色的东西。因此,对于一对 (X,Y),我在刻度上得到了一种颜色。所以我得到了 16 种可能的颜色。

这是一个说明我正在寻找的东西的传说:

我一直在查看在线示例,但不知道如何实现。

【问题讨论】:

  • 到目前为止你写了什么代码?

标签: javascript d3.js colors


【解决方案1】:

您可以很容易地将两个阈值尺度组合成一个新的尺度函数。该函数的核心可能如下所示:

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>

【讨论】:

  • 很好的例子,有很好的解释。绝对值得+1。这是否足够灵活,可以使用除颜色以外的其他东西吗?例如,您将如何修改它以使一个变量映射到颜色而另一个映射到透明度?还是使用像 interpolateViridis 这样的预定义比例?
  • 换句话说,你将如何修改它以能够使用 1°) 一个透明度比例和两个由 d3 预定义的比例,如 interpolateViridis?
  • 您应该能够使用渐变和不透明度,尽管使用.attr("fill".attr("opacity" 可能更简单。为了调整答案,而不是指定单个颜色通道,您可以指定基于绿色比例的 rgb 和具有第二个比例的 alpha(使用 d3.rgb 访问单个颜色) - 可能是这样的:jsfiddle.net/5Lo1afkw。要拥有一个可以进行渐变/不透明度或单独指定颜色通道组合的单个比例对象需要一些工作 - 如果使用带有颜色的纹理,则需要一种不同的方法来处理图案
  • 谢谢,这完全回答了我的问题。答复批准。希望我能再次投票,这很清楚,代码很好,有评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-30
  • 2019-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-24
  • 2010-12-28
相关资源
最近更新 更多