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

时间:2018-04-18 21:20:51

标签: 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);

我想要的更多内容

var mapdata = d3.map(data)
  .set(function(d) {d.county}, function(d) {d.rate});

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

提前致谢

3 个答案:

答案 0 :(得分:4)

当这样使用时:

.defer(d3.csv, 'employmentdata.csv') function(d) {
      map
      .set(d.county, +d.rate);
   })

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



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"));

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
&#13;
&#13;
&#13;

我们可以扩展它来操作键和值,因为行函数或forEach循环允许访问数据d,我们不需要在函数中实际包含操作:< / p>

&#13;
&#13;
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"));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
&#13;
&#13;
&#13;

你的第二个例子:

var mapdata = d3.map(data)
  .set(function(d) {d.county}, function(d) {d.rate});

这不起作用,因为.set只被调用一次,d未定义。实际上,根本不会调用这些函数。

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

   var mapdata = d3.map(data)

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

  

d3.map([object [,key]])&lt;&gt;

     

构造一张新地图。如果指定了object,则复制所有可枚举的对象   从指定对象到此映射的属性。指定的   对象也可以是数组或其他映射。可选的按键功能   可以指定计算数组中每个值的键。 (source

因此,您所看到的行为并非来自.set方法,而只来自默认索引:

&#13;
&#13;
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));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
&#13;
&#13;
&#13;

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

&#13;
&#13;
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);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
&#13;
&#13;
&#13;

这是一个有趣的行为,不仅在set方法中没有调用console.log,而且这两个函数被添加为数组中的键值对。它很容易被遗漏(很大程度上是由于堆栈片段和日志记录),但这里是地图的补充:

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

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

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

&#13;
&#13;
var data = [
  {key: "A", value: 100},
]

var map = d3.map(data);

map.set("B",function() { return "Hello"; })
        
console.log(map.get("B")());
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
&#13;
&#13;
&#13;

总结

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

&#13;
&#13;
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"));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
&#13;
&#13;
&#13;

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

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

如果你想在set方法中使用一个函数,你需要执行该函数并有一个返回值(在你的第二个例子/所需的代码中都缺少),你想要的功能是&#39;输出,而不是功能本身:

&#13;
&#13;
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(function() { return d.key + "-key"}(),
          double(d.value))
})

console.log(map.get("A-key"));

function double(n) { return n*2; }
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
&#13;
&#13;
&#13;

最后一点,您的初始(参考/起点)代码块没有正确设置,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);

应如下所示:

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);

上面的代码段使用相同的方法,创建地图,并为数组中的每个项目调用.set

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

答案 1 :(得分:0)

感谢您的解释。我尝试了上面的代码,它返回undefined。我可能知道问题是什么:

所以我目前的数据有多个类别。我想为不同的类别创建不同的键和值,我想通过将它们分配给新变量来区分它们。我想这样做是因为我想在我的地图上为不同的数据添加不同的功能,例如,我想根据失业率为地图着色,但我想根据不同的比率在地图上添加气泡,然后我想要根据其他内容创建下拉菜单。例如,我目前有:

 var nest = d3.nest()
    .key(function(d) {return d.occupation; })
    .entries(data);

   // array of locations in the data
   var nocs = nest.map(function(d) { return d.key; });

所以,当我创建我的下拉菜单时,我写下这个:

var nocMenu = d3.select('#dropDown')
    nocMenu
      .append("select")
      .attr("id", "selectMenu")
      .selectAll("option")
        .data(nest)   /// i'm using 'nest' now instead of the entire dataset
        .enter()
        .append("option")
        //.attr("value", function(d) { return d.values })
        .text(function(d) { return d.key; });

这给了我想要的东西。 topojson文件和csv文件之间的唯一关系是县名。我需要将县名作为关键,以失业为价值,以便在用地图填充地图时可以使用 d3.map()。get(d.properties.counties)

我试过了:

  var mMap = d3.map()
var mapdata = data.forEach(function(d) {
  mMap
    .set(d.geography, +d.rate)
});

console.log(mapdata);

但它返回undefined。

答案 2 :(得分:0)

作为 D3 版本 6,v6.4.0

package main; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.util.*; public class Main { /** * Iterate through each line of input. */ public static void main(String[] args) throws IOException { InputStreamReader reader = new InputStreamReader(System.in, StandardCharsets.UTF_8); BufferedReader in = new BufferedReader(reader); String line; while ((line = in.readLine()) != null) { long n = Long.parseLong(line); long result = getHeights(n); System.out.println(result); System.out.println(); } } static long getHeights(long n){ long result = 0; ArrayList<Long> heights = new ArrayList<>(); long left, right; int count = 0; for (int i = 0; i < n-1; i++) { long item = heights.size()>0?heights.get(i):n; if (heights.size() > 0) heights.remove(i); if (item % 2 == 0) { long step = item / 2; left = step; right = step; heights.add(count, left); heights.add(count, right); } else { left = 1; right = item - 1L; heights.add(0, left); heights.add(i==0?1:i,right); count++; } if (right >= 1){ result = (left * right) + result; } System.out.println(result + " " + Arrays.toString(heights.toArray())); } System.out.println(); return result; } } 没有参数给我错误:d3.map()。当降级到 v5 版本时,错误也会出现直到更改为 v4

以下是我的代码显示错误:

values is undefined