d3.map() 函数未返回预期结果

use*_*611 1 javascript arrays d3.js

我正在尝试将map.set(key, value)用于特定数据集 - 并将其分配给变量mapdata - 而不是在我将 csv 排队时指定它。

即,而不是:

d3.queue()
  .defer(d3.json, 'counties.json')
  .defer(d3.csv, 'employmentdata.csv') function(d) {
      d3.map()
      .set(d.county, +d.rate);
   })
  .await(ready);
Run Code Online (Sandbox Code Playgroud)

我想要更多的东西

var mapdata = d3.map(data)
  .set(function(d) {d.county}, function(d) {d.rate});
Run Code Online (Sandbox Code Playgroud)

除了代码没有返回我想要的。索引是键而不是县,值包括整个数据集而不仅仅是比率。我将如何解决这个问题?

提前致谢

And*_*eid 5

当这样使用时:

.defer(d3.csv, 'employmentdata.csv') function(d) {
      map
      .set(d.county, +d.rate);
   })
Run Code Online (Sandbox Code Playgroud)

map.set为 csv 中的每一行调用 with 回调函数,并单独设置每个键和值。如果你已经有一个数据数组,你可以用一个 forEach 循环来模拟它:

.defer(d3.csv, 'employmentdata.csv') function(d) {
      map
      .set(d.county, +d.rate);
   })
Run Code Online (Sandbox Code Playgroud)
var data = [
  {key: "A", value: 100},
  {key: "B", value: 200},
  {key: "C", value: 300},
  {key: "D", value: 400},
  {key: "E", value: 500}
]

var map = d3.map();
data.forEach(function(d) {
  map.set(d.key, d.value);
})

console.log(map.get("A"));
Run Code Online (Sandbox Code Playgroud)

我们可以扩展它来操作键和值,因为 row 函数或 forEach 循环允许访问 datum d,我们实际上不需要将操作包含在函数中:

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
var data = [
  {key: "A", value: 100},
  {key: "B", value: 200},
  {key: "C", value: 300},
  {key: "D", value: 400},
  {key: "E", value: 500}
]

var map = d3.map();
data.forEach(function(d,i) {
  map.set(d.key+"-"+i, d.value*2);
})

console.log(map.get("A-0"));
Run Code Online (Sandbox Code Playgroud)


你的第二个例子:

var mapdata = d3.map(data)
  .set(function(d) {d.county}, function(d) {d.rate});
Run Code Online (Sandbox Code Playgroud)

这将不起作用,因为.set它只被调用一次,并且d没有定义。事实上,这些函数根本不会被调用。

在我们查看 set 方法中的函数之前,让我们仔细看一下第一行:

   var mapdata = d3.map(data)
Run Code Online (Sandbox Code Playgroud)

d3.map 需要两个参数,一个定义数据数组,另一个定义键。由于您不提供密钥,因此使用默认密钥,索引:

d3.map([object[, key]]) <>

构建新地图。如果指定了对象,则将指定对象中的所有可枚举属性复制到此映射中。指定的对象也可以是数组或其他映射。可以指定一个可选的键函数来计算数组中每个值的键。(来源

因此,您看到的行为不是来自.set方法,而是来自默认索引:

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
var mapdata = d3.map(data)
  .set(function(d) {d.county}, function(d) {d.rate});
Run Code Online (Sandbox Code Playgroud)

那么.set在你的例子中做了什么?它正在向您的数据集添加一个新的值键对,让我们仔细看看之前和之后的地图:

   var mapdata = d3.map(data)
Run Code Online (Sandbox Code Playgroud)
var data = [
  {key: "A", value: 100},
  {key: "B", value: 200},
  {key: "C", value: 300},
  {key: "D", value: 400},
  {key: "E", value: 500}
]

var map = d3.map(data);

console.log(map.get(0));
Run Code Online (Sandbox Code Playgroud)

这是一个有趣的行为,不仅console.log在 set 方法中没有调用 s,这两个函数被添加为数组中的键值对。很容易错过(主要是由于堆栈片段的日志记录),但这是地图的补充:

"$function (d) { console.log(d); }": function (d) { console.log(d); },

set 方法只会添加一个键值对,它不会修改现有的键值对(除非覆盖一个)。这就是为什么 .set 将在行函数或 forEach 循环中工作,但在设置多个键/值对时则不然。

虽然作为键的函数被强制转换为字符串,但您可以将函数作为值嵌入:

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
var data = [
  {key: "A", value: 100},
  {key: "B", value: 200},
  {key: "C", value: 300},
  {key: "D", value: 400},
  {key: "E", value: 500}
]

var map = d3.map(data);

console.log(map);
console.log("---------------");

map.set(function(d) { console.log(d); },
        function(d) { console.log(d); })
        
console.log(map);
Run Code Online (Sandbox Code Playgroud)


加起来

因此,如果您想使用键和整个对象作为值创建地图,您可以使用:

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
var data = [
  {key: "A", value: 100},
]

var map = d3.map(data);

map.set("B",function() { return "Hello"; })
        
console.log(map.get("B")());
Run Code Online (Sandbox Code Playgroud)

但是如果你想为每个键指定一个特定的值(而不是数据数组项),使用 forEach 循环会更容易(如本答案的第一个片段所示):

var map = d3.map()
data.forEach(function(d) {
  map.set(d.key,d.value)
})
Run Code Online (Sandbox Code Playgroud)

如果要在此处的 set 方法中使用函数,则需要执行该函数并具有返回值(在第二个示例/所需代码中都没有),您需要函数的输出,而不是函数本身:

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
var data = [
  {key: "A", value: 100},
  {key: "B", value: 200},
  {key: "C", value: 300},
  {key: "D", value: 400},
  {key: "E", value: 500}
]

var map = d3.map(data, function(d) { return d.key; });

console.log(map.get("A"));
Run Code Online (Sandbox Code Playgroud)


最后一点,您的初始(参考/起点)代码块设置不正确,d3.map() 创建了一个新地图。我们不想为每一行创建一个新地图,我们想创建一次地图,然后为每一行使用 set。

因此:

d3.queue()
  .defer(d3.json, 'counties.json')
  .defer(d3.csv, 'employmentdata.csv') function(d) {
      d3.map()
      .set(d.county, +d.rate);
   })
  .await(ready);
Run Code Online (Sandbox Code Playgroud)

应该是这样的:

var map = d3.map();  // create a map.
d3.queue()
  .defer(d3.json, 'counties.json')
  .defer(d3.csv, 'employmentdata.csv') function(d) {
      map // use that same map for each row.
      .set(d.county, +d.rate);
   })
  .await(ready);
Run Code Online (Sandbox Code Playgroud)

上面的片段使用相同的方法,创建一个映射,并调用.set数组中的每个项目。

相反,类似 :d3.map().get(d.property)不会返回任何内容,因为您刚刚创建了一个空的新地图d3.map()