简体   繁体   中英

Simultaneously extracting list of dimensions and creating scale for each in d3.js - Expand on process?

As a beginner of D3 I'd like to know more about whats going on in this command step by step. Please help me understand how the lists are formed and how they are prescribed individual scales using the command.

Can this command be broken up into separate blocks? - such as one for list creation, and another for yAxis definition

   var x = d3.scale.ordinal().rangePoints([0, width], 1),
   y = {};

  // Extract the list of dimensions and create a scale for each.
  x.domain(dimensions = d3.keys(cars[0]).filter(function(d) {
    return d != "name" && (y[d] = d3.scale.linear()
        .domain(d3.extent(cars, function(p) { return +p[d]; }))
        .range([height, 0]));
  }));

Data for this is

name,economy (mpg),cylinders,displacement (cc),power (hp),weight (lb),0-60 mph (s),year
AMC Ambassador Brougham,13,8,360,175,3821,11,73
AMC Ambassador DPL,15,8,390,190,3850,8.5,70
AMC Ambassador SST,17,8,304,150,3672,11.5,72

Source: https://bl.ocks.org/mbostock/1341021

That's a very elegant way to create an object named y with several different linear scales, one for each categorical variable in the x axis (since we're dealing with a parallel coordinates chart).

Here is the logic:

First, Bostock (the author of that code) declares an ordinal scale for the x axis...

var x = d3.scale.ordinal().rangePoints([0, width], 1)

... and an empty object:

var y = {}

So far, nothing unusual.

Then we get to the block that puzzled you. Let's break it up.

It defines the domain of the x scale, at the same time that creates a global named dimensions :

x.domain(dimensions = d3.keys(cars[0]).filter(function(d) {
    return d != "name"
}));

dimensions is in fact just an array of strings...

["economy (mpg)",
    "cylinders",
    "displacement (cc)",
    "power (hp)",
    "weight (lb)",
    "0-60 mph (s)",
    "year"
]

... made with d3.keys(cars[0]) , filtering out the name column.

However, inside the filter function, it is populating the y object:

y[d] = d3.scale.linear()
    .domain(d3.extent(cars, function(p) {
        return +p[d];
    }))
    .range([height, 0]);

For every column (that is, every value in dimensions array), except name , it's creating an scale (since false && anything is short-circuit evaluated to false , and the anything part is just ignored, there will be no y scale for the name column).

So, if d in one particular iteration is cylinders , it will create this property in the y object:

y["cylinders"] = d3.scale.linear()
    .domain(d3.extent(cars, function(p) {
        return +p["cylinders"];
    }))
    .range([height, 0]))

At the end, if you console.log(y) , you're gonna see an object with all the scales, like this (my ridiculous attempt to imitate the Chrome console):

> Object
    > 0 - 60 mph(s): u(n)
    > cylinders: u(n)
    > displacement(cc): u(n)
    > economy(mpg): u(n)
    > power(hp): u(n)
    > weight(lb): u(n)
    > year: u(n)
    > __proto__: Object

Post Scriptum : a mere mortal, like me, would write that code in a much more humble way:

dimensions = d3.keys(cars[0]).filter(function(d) {
    return d != "name";
});

x.domain(dimensions);

dimensions.forEach(function(d) {
    y[d] = d3.scale.linear()
        .domain(d3.extent(cars, function(p) {
            return +p[d];
        }))
        .range([height, 0])
})

And the result is the same. Here is the bl.ocks to show it: https://bl.ocks.org/anonymous/87b926c85b8385aecdab722c74c4d2ef

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM