d3.scale.20级对我来说太聪明了
d3.scale.category20 is too smart for me
谁能给我解释一下为什么这两个表达式返回不同的值…
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>
- javascript中的闭包对我来说工作方式不同
- Rails JQuery和Ajax对我来说工作不正常
- 如果使用单个实体,使用automapper对我来说很好
- css animate fadeIn'对我来说不起作用
- 对我来说,用javascript设置这个函数最有效的方法是什么
- 文本中的函数示例对我来说没有意义
- 使用 jQuery 编写一个可排序的列表(只是基本功能,jQueryUI 对我来说太重了)
- 通过body onload使用json_encode发送数组对我来说不起作用
- 对我来说,以排序的方式检索这些信息的最佳方式是什么
- javascript有两个奇怪的bug(至少对我来说)
- 在同一个按钮上调用多个函数对我来说不起作用(ajax)
- RegExp(对我来说)并不那么简单
- jQuery's的slideUp功能对我来说无法正常工作
- javascript中的单元测试:如何模拟?-一个(对我来说很难)的例子
- 倒数第二的第n个孩子没有'对我来说不起作用
- 我应该将php json编码转换为Ajax数组,第一次对我来说很难理解
- 否则if语句对我来说似乎是合理的,但会破坏代码
- Node.js事件循环对我来说没有意义
- Javascript -检查页面加载时是否存在cookie对我来说不起作用
- d3.scale.20级对我来说太聪明了