Home Looping through array of objects within multiple objects and accessing values in D3 using underscore
Reply: 1

Looping through array of objects within multiple objects and accessing values in D3 using underscore

vw88
1#
vw88 Published in 2018-02-13 08:10:57Z

In D3d.js, I'm trying to append rectangles for each object in the array, so the height of the rectangle is determined by the value. Also, I'm trying to make it so only the first object in each array shows first, and then when you click a button it cycles through the 2nd and 3rd object.

However I'm having issues looping through the data because not sure how to do it with this JSON structure--

  var data= {
    "Object_one":[
        {"date":"1/4/2010",
         "value":"50",},
        {"date":"6/22/2010",
         "value":"44",},
        {"date":"9/18/2010",
         "value":"42",},
    ],
    "Object_two":[
        {"date":"1/4/2010",
         "value":"54",},
        {"date":"6/22/2010",
         "value":"41",},
        {"date":"2012",
         "value":"42",},
    ],
    "Object_three":[
        {"date":"1/4/2010",
         "value":"55",},
        {"date":"6/22/2010",
         "value":"43",},
        {"date":"9/18/2010",
         "value":"65",},
    ]
}

I have a loop set up using underscore.js to loop through the data, but it's only taking in all the objects of the first array, as opposed to the first object in each array for each Object X.

https://jsfiddle.net/vw88/6Ljekv45/

(see line 55 of the js for the part that appends the rectangles with values)

Shashank
2#
Shashank Reply to 2018-02-13 15:29:16Z

The way the data is being bound to the rects is incorrect:

var levels = levelsHolder.selectAll('rect.square-levels')
.data(data[key])

results in assigning data["Object one"], then data["Object two"] and so on which enters rects for just data["Object one"] in the first iteration i.e. 3 rects and as there's no update method used, the rects stay as they are resulting in 3 rectangles corresponding to the data["Object one"] array elements.

A solution would be to use the data's keys and map the array's first elements as follows:

var levels = levelsHolder.selectAll('rect.square-levels')
.data(Object.keys(data).map(function(k) { return data[k][0]; }))

Now, I'm being nice and providing you the function for the button click as well (just kidding). Anyway, I'm using two variables "initial" and "max" which goes from 0 through maximum array length in the data and accordingly changes the bound data to the rects. And yes, it can be done using underscore.js as well but I didn't find the need of it here.

Button on click:

d3.select('#myButton').on('click', function() {
   initial++;
   if(initial > max) { initial = 0; }
   levels.data(Object.keys(data).map(function(k) { return data[k][initial]; }));

   drawSquares();
});

Here's a code snippet using the above logic (its not the best of logics but you can change it as per your requirements):

var data= {
	"Object one":[
		{"date":"2010",
		 "value":"80",},
		{"date":"2011",
		 "value":"94",},
		{"date":"2012",
		 "value":"50",},
	],
  	"Object two":[
		{"date":"2010",
		 "value":"104",},
		{"date":"2011",
		 "value":"41",},
		{"date":"2012",
		 "value":"92",},
	],
  	"Object three":[
		{"date":"2010",
		 "value":"75",},
		{"date":"2011",
		 "value":"43",},
		{"date":"2012",
		 "value":"85",},
	],
   "Object four":[
		{"date":"2010",
		 "value":"75",},
		{"date":"2011",
		 "value":"43",},
		{"date":"2012",
		 "value":"85",},
	]
}


  var margin = {top: 30, right: -3, bottom: 30, left:0},
  width = parseInt(d3.select('#holder').style('width'),10)
  width = width - margin.left - margin.right,
  height = width/2;
  
  var initial = 0, max = data['Object one'].length-1;

  var mainChartSVG = d3.select('#holder')
    .append('svg')
    .attr('width', width)
    .attr('height', height)

  var frameHolder = mainChartSVG.append('g')
    .classed('holder-frames',true);

  // Draw squares to show levels

  var maxValue = d3.max(data, function(d){
    return d.value;
  });

  var valueScale = d3.scale.linear()
    .domain([0,100])
    .range([50,0]);

  var levelsHolder = mainChartSVG.append('g')
    .classed('holder-levels',true);
    
  var levels = levelsHolder.selectAll('rect.square-levels')
    .data(Object.keys(data).map(function(k) { return data[k][initial]; }))
    .enter().append('rect')
    .classed('square-levels', true);
    
	function drawSquares() {
      levels
        .attr({
          x: function(d, i){
             return i % 5 * width/5
          },
          y: function(d, i){
             return valueScale(d.value)+(Math.floor(i / 5) * width/5)
          },
        width: width/5-3,
        height: function(d) {
          return (width/5-3)-valueScale(d.value) ;
        },
        fill:"red",
        class: function(d) { return d.value; }
    })
}
drawSquares();

var frameHolder = mainChartSVG.append('g')
    .classed('holder-frames',true);

  var keyarray = Object.keys(data)

  var frames = frameHolder.selectAll('rect.square-frame')
    .data(keyarray)
    .enter().append('rect')
    .classed('square-frame', true)
    .attr({
      x:function(d, i){
        //console.log(d, "D VALUE")
        return i % 5 * (width/5 )
      },
      y:function(d, i){
        return Math.floor(i / 5) * (width/5 )
      },
      width: width/5-3,
      height: width/5-3,
    })

d3.select('#myButton').on('click', function() {
	initial++;
  if(initial > max) { initial = 0; }
  levels.data(Object.keys(data).map(function(k) { return data[k][initial]; }));
  
	drawSquares();
});
body{
  background-color:white;
}

.square-frame{
  stroke: #38434f;
  fill: none;
}

a {
  text-decoration: none;
  display: inline-block;
  padding: 3px 8px;
  margin-bottom: 2em;
}

a:hover {
  background-color: gray;
  color: black;
}

#myButton {
  background-color: #e5e5e5;
  color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<a href="#" id="myButton">&#8250;</a>
<div id="holder"></div>

Hope this helps. Let me know if you come across any questions.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.335861 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO