When used as such:
.defer(d3.csv, 'employmentdata.csv') function(d) {
map
.set(d.county, +d.rate);
})
The callback function with map.set is called for each row in the csv, and each key and value is set individually. If you have an array of data already, you can emulate this with a forEach loop:
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>
We can expand this to manipulate the key and value, as the row function or a forEach loop allows access to the datum d, we don't need to actually enclose the manipulation in a function:
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"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Your second example:
var mapdata = d3.map(data)
.set(function(d) {d.county}, function(d) {d.rate});
This will not work because .set is only being called once, and d is not defined. In fact, the functions will not be called at all.
Before we look at the functions in the set method, let's look at the first line a little closer:
var mapdata = d3.map(data)
d3.map expects two parameters, one defining the data array, and one defining the key. As you don't provide a key, the default key is used, index:
d3.map([object[, key]]) <>
Constructs a new map. If object is specified, copies all enumerable
properties from the specified object into this map. The specified
object may also be an array or another map. An optional key function
may be specified to compute the key for each value in the array. (source)
So, the behavior you are seeing doesn't come from the .set method but simply from the default indexing:
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));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
So what is .set doing in your example? It is adding a new value key pair to your dataset, let's take a close look at the map before and after:
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);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
This is interesting behavior, not only are the console.logs not called in the set method, the two functions are added as key, value pairs in the array. It's easy to miss (largely due to stack snippet's logging), but here's the addition to the map:
"$function (d) { console.log(d); }": function (d) { console.log(d); },
The set method will only add one key value pair, it will not modify existing pairs (unless to overwrite one). This is why .set will work in a row function or a forEach loop, but not otherwise when setting multiple key/value pairs.
While the function that was key was coerced to a string, you could embed functions as values:
var data = [
{key: "A", value: 100},
]
var map = d3.map(data);
map.set("B",function() { return "Hello"; })
console.log(map.get("B")());
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Summing Up
So, if you want to create a map using a key and the whole object as a value you can use:
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"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
But if you want to specify a certain value for each key (as opposed to the data array item), it will be easier to use a forEach loop (as seen in the first snippet in this answer):
var map = d3.map()
data.forEach(function(d) {
map.set(d.key,d.value)
})
If you want to use a function in the set method here, you would need to execute the function and have a return value (both missing in your second example/desired code), you want the function's outputs, not the function itself:
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; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
A last note, your initial (reference/starting point) code block isn't quite set up properly, d3.map() creates a new map. We don't want to create a new map for each row, we want to create a map once and then use set for each row.
Consequently this:
d3.queue()
.defer(d3.json, 'counties.json')
.defer(d3.csv, 'employmentdata.csv') function(d) {
d3.map()
.set(d.county, +d.rate);
})
.await(ready);
Should read like:
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);
The snippets above use this same approach, create a map, and call .set for each item in the array.
Conversely, something like : d3.map().get(d.property) won't return anything because you've just created a new map which is empty with d3.map().
id,county,rate,occ,education 01,place1,80,'Business & Administration",Bachelor's Degree,0 02,place2,15,'applied sciences',Certificate/Diploma,12