d3.scale.20级对我来说太聪明了

d3.scale.category20 is too smart for me

本文关键字:对我来说 scale 20级 d3      更新时间:2023-09-26

谁能给我解释一下为什么这两个表达式返回不同的值…

log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"

…在以下上下文中


工作示例…

    var c20 = d3.scale.category20(),
      col = d3.range(20).map(function(c) {
        return c20(c).replace("#", "0x")
      }),
      log1 = d3.select("#log1"),
      log2 = d3.select("#log2");
    log1.text(c20(1)); // "#aec7e8"
    log2.text(d3.scale.category20()(1)); // "#1f77b4"
    $("#user-agent").text(navigator.userAgent);
#log div {
  display: inline-block;
  margin: 0 0 0 10px;
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<div id="log">
  <div id="log1"></div>
  <div id="log2"></div>
</div>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <div id="container"></div>
  <p id="user-agent"></p>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
  <div id="log1"></div>
  <div id="log2"></div>
</body>
</html>

我的系统中报告的用户代理是

Mozilla/5.0 (Windows NT 6.1;WOW64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/45.0.2454.85 Safari/537.36


我有点理解上面的行为,但这是非常奇怪的…

为什么…

// method 1
d3.range(20).map(d3.scale.category20())
0   #1f77b4
1   #aec7e8
2   #ff7f0e
3   #ffbb78
4   #2ca02c
5   #98df8a
6   #d62728
7   #ff9896
8   #9467bd
9   #c5b0d5
10  #8c564b
11  #c49c94
12  #e377c2
13  #f7b6d2
14  #7f7f7f
15  #c7c7c7
16  #bcbd22
17  #dbdb8d
18  #17becf
19  #9edae5

不同于这个…

// method 2
d3.range(20).map(function(d, i) {
    return d3.scale.category20()(i);
})  
0   #1f77b4
1   #1f77b4
2   #1f77b4
3   #1f77b4
4   #1f77b4
5   #1f77b4
6   #1f77b4
7   #1f77b4
8   #1f77b4
9   #1f77b4
10  #1f77b4
11  #1f77b4
12  #1f77b4
13  #1f77b4
14  #1f77b4
15  #1f77b4
16  #1f77b4
17  #1f77b4
18  #1f77b4
19  #1f77b4

var c20 = d3.scale.category20(),
  log1 = d3.select("#log1"),
  log2 = d3.select("#log2");
log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"
d3.select("#t1").selectAll(".logs")
  .data(d3.range(20).map(d3.scale.category20()))
  .enter().append("tr").selectAll("td").data(function(d) {
    return [d]
  })
  .enter().append("td")
  .attr("class", "logs")
  .text(function(d, i, j) {
    return [j, d].join("'t")
  })
d3.select("#t2").selectAll(".logs")
  .data(d3.range(20).map(function(d, i) {
    return d3.scale.category20()(i);
  }))
  .enter().append("tr").selectAll("td").data(function(d) {
    return [d]
  })
  .enter().append("td")
  .attr("class", "logs")
  .text(function(d, i, j) {
    return [j, d].join("'t")
  })
#log div {
  display: inline-block;
  margin: 0 0 10px 10px;
  background: #ccc;
}
#t1,
#t2 {
  background: #ccc;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<div id="log">
  <div id="log1"></div>
  <div id="log2"></div>
</div>
<div id="t1"></div>
<div id="t2"></div>

只是解释一下,我想使用上面方法2的原因是因为我需要将十六进制字符串转换为格式正确的十六进制数字,所以我必须在此过程中处理域值。实际的用例是这样的:

var col = d3.range(20).map(function(c){
        return d3.scale.category20()(c).replace("#", "0x")
    });  

不能工作(我仍然不明白为什么不能),这就是为什么我必须这样做的原因:

var c20 = d3.scale.category20(),
    col = d3.range(20).map(function(c){
        return c20(c).replace("#", "0x")
    });

您可以考虑在使用调色板时"构建"它。如果你在顶部创建调色板,例如

var palette = d3.scale.category20();

并在迭代中应用调色板的不同值(例如

)

selection.style('fill', function(d, i) {return palette(i);});

则在每次调用时,调色板检查它是否已经为该值分配了颜色;如果没有,它将尝试给出一个新的颜色(或回收,如果你没有颜色)。

相反,如果您在迭代中将该值应用于一个新的调色板,则它将始终从中提取一个值,该值来自于一个特定的调色板:

selection.style('fill', function(d, i) {return d3.scale.category20()(i);});

不希望的结果是所有的颜色都是一样的。

也就是说,d3.scale.category20不是一个纯函数;它隐式地跟踪它的状态。这类似于使用接受种子的随机数生成,即确定性:您不想在迭代中重新创建它,否则您提取的随机数将始终是相同的。

这个问题(D3v4之前)说明了函数式编程的一般价值,因为预期使用某些值调用的函数总是依赖于提供的参数,这也使测试更容易。

这似乎是一个问题与d3js代码的有序尺度函数。在Chrome 47.0.2502.0金丝雀上运行此操作时,d3.scale.category20()(c)总是返回#1f77b4,无论c的值是什么。#1f77b4是20种颜色列表中的第一个值

更新的代码片段。

var c20 = d3.scale.category20(),
      col = d3.range(20).map(function(c){
        console.log(c20(c), d3.scale.category20()(c))
        // d3.scale.category20()(c) is always #1f77b4
        return c20(c).replace("#", "0x")
      }),
      log1 = d3.select("#log1"),
      log2 = d3.select("#log2");
    log1.text(c20(1)); // "#aec7e8"
    log2.text(d3.scale.category20()(1)); // "#1f77b4"
    $("#user-agent").text(navigator.userAgent);
#log div {
  display: inline-block;
  margin: 0 0 0 10px;
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<div id="log">
  <div id="log1"></div>
  <div id="log2"></div>
</div>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <div id="container"></div>
  <p id="user-agent"></p>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
  <div id="log1"></div>
  <div id="log2"></div>
</body>
</html>