Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3: A sub array of objects

I have the following structure:

[
    { 'length': 10, attributes: [1,2,3] },
    { 'length': 7, attributes: [1,3,4,5] },
    { 'length': 12, attributes: [3,5,7,9,10] },
]

 and I am doing the following:


x = d3.scale.linear().domain([0, maxHeight]).range([50, w]),
y = d3.scale.linear().domain([0, maxHeight]).range([h, 20]);
z = d3.scale.linear().domain([0, maxHeight]).range([0, h - 20]);

var chart = svg.selectAll("g.chart")
    .data(items)
    .enter()
    .append("svg:g")
    .attr("class", "chart");

chart.append("svg:rect")
    .attr("fill", 'darkblue')
    .attr("class", 'data')
    .attr("x", function(d, i) { return x(i+1); })
    .attr("y", function(d, i) { return bottom - z(d['length']) + 15 })
    .attr("width", 4)
    .attr("height", function(d, i)  { return z(d['length']) - z(d['min']); })

What I would like to do is add circles on each of these rectangles which corresponds to the attributes in my structure. Basically, (for one 'item'}, I should see something like this:

<g class="chart">
    <rect fill="darkblue" class="data" x="626.1538461538462" y="15" width="6" height="530"></rect>
    <circle cx="626.1538461538462" cy="(y1)" r="5" style="fill: #ffff00; stroke: #808080;"></circle>
    <circle cx="626.1538461538462" cy="(y2)" r="5" style="fill: #ffff00; stroke: #808080;"></circle>
    <circle cx="626.1538461538462" cy="(y3)" r="5" style="fill: #ffff00; stroke: #808080;"></circle>
</g>

The only thing I can think of is looping over the attributes and adding them element by element:

for (z=0; z< 3; ++z)
{
    chart.append("svg:circle")
    .data(items[z]['attributes'])
    .style("fill", 'yellow')
    .style("stroke", "gray")
    .attr("cx", function(d, i) { return x(i+1); })
    .attr("cy", function(d, i) 
    { 
        console.log(d); 
        return bottom - 15;
    })
    .attr("r", 5);
}

Is there a better way to do this?

like image 487
Paul Avatar asked Dec 10 '13 22:12

Paul


People also ask

What is D3 range?

d3. range returns an array of evenly-spaced numbers. In its simplest form, it returns the integers from zero to the specified end minus one.

What is D3 extent?

extent() function in D3. js is used to returns the minimum and maximum value in an array from the given array using natural order. If an array is empty then it returns undefined, undefined as output.

What is D3 select?

select() function in D3. js is used to select the first element that matches the specified selector string. If any element is not matched then it returns the empty selection. If multiple elements are matched with the selector then only the first matching element will be selected.

What does D3 map do?

Use d3. map to group items together, creating a hashed array that can be accessed using handy functions like array. get(value) .


1 Answers

You can created a nested selection instead of looping:

chart.selectAll("svg:circle")
    .data(function(item) { return item.attributes; })
  .enter()
    .append("svg:circle")
    .style("fill", 'yellow')
    .style("stroke", "gray")
    .attr("cx", function(d, i) { return x(i+1); })
    .attr("cy", function(d, i) 
    { 
        console.log(d); 
        return bottom - 15;
    })
    .attr("r", 5);

Example:

To keep the cx the same for each parent rect, you can pass the parent_idx through

chart.selectAll("svg:circle")
    .data(function(item, parent_idx) { 
        return item.attributes.map(function (attr_val) {
                 return { attr_val: attr_val, parent_idx: parent_idx };
            });
    })
  .enter()
    .append("svg:circle")
    .style("fill", 'yellow')
    .style("stroke", "gray")
    .attr("cx", function(d, i) { return x(d.parent_idx); })
    .attr("cy", function(d, i) 
    { 
        return y(d.attr_val);
    })
    .attr("r", 5);
like image 181
musically_ut Avatar answered Oct 06 '22 01:10

musically_ut