javascript d3.scale.category20 对我来说太聪明了

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32422325/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 15:14:53  来源:igfitidea点击:

d3.scale.category20 is too smart for me

javascriptd3.js

提问by Cool Blue

Can anybody explain to me why these two expressions return different values...

谁能向我解释为什么这两个表达式返回不同的值...

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

... in the following context

...在以下上下文中



Working example...

工作示例...

    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>

The user agent reported in my system is

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

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

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



I kind of get the above behaviour but this is very strange...

我有点得到上述行为,但这很奇怪......

Why is this...

为什么是这样...

// 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

different from this...

与此不同...

// 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>

Just to explain, the reason I wanted to use method 2 above was because I needed to convert the hex strings into properly formatted hex numbers so I had to process the domain values on the way through. The actual use case is this:

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

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

which doesn't work (and I still don't get why not), which is why I had to do this:

这不起作用(我仍然不明白为什么不这样做),这就是为什么我必须这样做:

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

回答by Robert Monfera

You can think of the palette 'building up' as it's being used. If you create the palette on the top, e.g.

您可以将调色板想象成“正在使用”。如果您在顶部创建调色板,例如

var palette = d3.scale.category20();

var palette = d3.scale.category20();

and apply the palette different values in an iteration (e.g.

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

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

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

then on each invocation, the palette checks if it already assigned a color for that value; if not, it'll attempt to give a new color (or recycle if you run out of colors).

然后在每次调用时,调色板检查它是否已经为该值分配了颜色;如果没有,它会尝试赋予新颜色(如果颜色用完,则回收)。

In contrast, if you apply the value to a fresh palette in your iteration, it'll always just pull one value from that one specific palette:

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

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

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

The undesirable result is that all colors will be the same.

不希望的结果是所有颜色都相同。

In other words, the d3.scale.category20isn't a pure function; it implicitly keeps track of its state. It's similar to e.g. using a random number generation that accepts a seed, i.e. deterministic: you don't want to recreate it in an iteration, otherwise the random number you pull will always be the same.

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

This issue (pre D3v4) speaks to the general value of functional programming, as there's anticipation that a function called with some values will always depend on just the supplied arguments, making testing easier too.

这个问题 (pre D3v4) 说明了函数式编程的一般价值,因为预期使用某些值调用的函数将始终仅依赖于提供的参数,从而也使测试更容易。

回答by widged

It seems to be an issue with the d3js code for the ordinal scale function. When running this on Chrome 47.0.2502.0 canary, d3.scale.category20()(c) always returns #1f77b4, whatever the value of c is. #1f77b4is the first value in the list of 20 colors

序数比例函数的 d3js 代码似乎有问题。在 Chrome 47.0.2502.0 canary 上运行它时,d3.scale.category20()(c) 总是返回#1f77b4,无论 c 的值是什么。#1f77b420 种颜色列表中的第一个值

Updated snippet.

更新的片段。

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>