简体   繁体   中英

d3 nested variable data binding

I'm a newbie to D3 and trying to solve a not so easy problem (at least to me!) Here's my sample dataset.

var data = [
    {"x":1000, "y": {"10":100, "10.2":200, "10.3":300, "10.4":600}},
    {"x":1001, "y": {"9.2":60, "9.6":400, "10.1":20, "10.8":320, "11":20, "8.8":722}},
    {"x":1002, "y": {"9.8":80, "9.9":600, "9.2":40}},
    {"x":1003, "y": {"10.1":60, "10.3":400, "10.8":360, "9.6":88}},
    {"x":1004, "y": {"9.8":20, "10.4":450}}
];

How can I bind this using d3 to create rectangles with the attributes x= value of x, y= keys of the y object, width= values of the y object and height= any given constant?

Essentially, this will have a variable number of rectangles for each x based on the number of elements in the y object.

This is, indeed, a little bit complicated, mainly because your y property contains just one object, instead of an array of objects.

My solution here uses d3.entries , which, according to the API :

Returns an array containing the property keys and values of the specified object (an associative array). Each entry is an object with a key and value attribute, such as {key: "foo", value: 42}. The order of the returned array is undefined. (emphasis mine)

It's important having an array, so we can bind the data (since the data() method accepts only three things: an array, a function or nothing).

So, in this solution, I'm using the outer objects to append groups...

var groups = svg.selectAll(null)
  .data(data)
  .enter()
  .append("g");

... and the y object of each outer object to append the rectangles...

var rects = groups.selectAll(null)
  .data(function(d) {
    return d3.entries(d.y)
  })
  .enter()
  .append("rect");

... and using d3.entries() to convert the object into an array of objects, which can be used with data() .

Here is a demo (I changed your actual values, so we can better see the rectangles):

 var data = [{ "x": 100, "y": { "10": 100, "20": 200, "26": 300, "35": 400 } }, { "x": 20, "y": { "50": 60, "59.6": 400, "70.1": 20, "80.8": 320, "88": 20, "98.8": 722 } }, { "x": 30, "y": { "109.8": 80, "119.9": 600, "139.2": 40 } }, { "x": 10, "y": { "150.1": 60, "170.3": 400, "190.8": 360, "209.6": 88 } }, { "x": 50, "y": { "259.8": 20, "280.4": 450 } }]; var colours = d3.scaleOrdinal(d3.schemeCategory10); var constant = 5; var svg = d3.select("svg"); var groups = svg.selectAll(null) .data(data) .enter() .append("g") .style("fill", function(d, i) { return colours(i) }) var rects = groups.selectAll(null) .data(function(d) { return d3.entries(dy) }) .enter() .append("rect"); rects.attr("y", function(d) { return +d.key }) .attr("width", function(d) { return d.value }) .attr("height", constant) .attr("x", function(d) { return d3.select(this.parentNode).datum().x; })
 <script src="https://d3js.org/d3.v4.min.js"></script> <svg width="600" height="300"></svg>

Pay attention to how I get the y and width values and, specially, the x value (accessing the parent's datum).

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