-1

I am working on creating a bubble chart with D3 and I can build the chart just fine with dummy data, but when I try to consume my live data the chart won't work. I understand why it doesn't work, it's because the data is coming in, in a bad format for D3. I just don't know how to reorganize the data with JavaScript.

My data is stored in an object like this:

datas = {fieldA:[Array[32]], fieldB[Array[32]]};

And the Array inside of the properties looks like this:

Array[Object,Object,Object...]

The data I need is a property in the array of objects called raw_data

So to access one of the data points it would look something like this:

datas.fieldA[0].raw_data

I need the data to be accessed like this:

datas[0].fieldA.raw_data

This will allow me to bind datas in my D3 viz and have access to both fieldA and fieldB. Right now, I can bind datas.fieldA which is an issue because I need both fields to create the viz.

Below is the actual d3 code I am writing if that helps. I can create the circles, but now need to append text to the circles. The real field names are countword and word.

    var h = options.dataset.chart_information.height;
    var w = options.dataset.chart_information.width;
    var margin = {left:5, right:5, top:5, bottom:5};
    var dataWord = options.dataset.data.countword;
    var dataText = options.dataset.data.word;



    var simulation = d3.forceSimulation()
                        .force("x", d3.forceX(w/2).strength(0.05))
                        .force("y", d3.forceY(h/2).strength(0.05))
                        .force("collide", d3.forceCollide(function(d) { return rScale(d.raw_data) + 0.2; }));

    var rScale = d3.scaleSqrt()
                    .domain([d3.min(dataWord, function(d) { return d.raw_data; }), 
                            d3.max(dataWord, function(d) { return d.raw_data; })])
                    .range([10,60]);

    var svg = d3.select(options.divSelector)
                .append("svg")
                .attr("height",h)
                .attr("width",w);

    var circles = svg.selectAll(".circle")
                    .data(dataWord)
                    .enter()
                    .append("circle")
                        .attr("r", function(d) { return rScale(d.raw_data); })
                        .attr("fill","steelblue");

    simulation.nodes(dataWord)
                .on("tick", ticked);

    function ticked() {
        circles
            .attr("cx", function(d) { return d.x })
            .attr("cy", function(d) { return d.y });
    };
  • It seems like you should process your data first, then call a function to render the chart. This is really more of a data question than a d3 question. You might want to look at some lodash helpers. – Union find Mar 25 '17 at 13:19

3 Answers3

2

This is a functional approach working on arrays. Please note that the count of objects in result will be the minimum of all fields (fieldA and fieldB in this case). That can only be a problem if fields differ in length. I put some console.logs in between to explain the steps on the way. Obviously those logs and the variable assignments aren‘t necessary - the code can be shortened… Object.assign is ES2015 (ES6) code - if that‘s a problem it has to substituted, maybe like here

var datas = {fieldA:[ { rawdata:'a1'}, { rawdata:'a2' }, { rawdata:'a3' } ], fieldB: [ { rawdata:'b1'}, { rawdata:'b2'} ]};

// transform each field to contain it‘s name
var fields = Object.keys(datas).map(function(fieldName) {
  return datas[fieldName].map(function(value) {
    let object = {};
    object[fieldName] = value;
    return object;
  });
});
console.log(fields);

// use d3.zip to transpose
var zipped = d3.zip.apply(null, fields);
console.log(zipped);

// merge objects in array
var result = zipped.map(function(objects) {
  return Object.assign.apply(null, objects);
});

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Community
  • 1
  • 1
undko
  • 927
  • 8
  • 15
  • 1
    This worked like a charm! Even though you were using version 3 of D3 everything in this code block is the same on v4. You are a javascript data ninja! – Thomas Linton Mar 25 '17 at 18:24
  • I was just lazy. The snippet tool wouldn‘t offer v4 and I presumed there was no change in `d3.zip` since v3… – undko Mar 25 '17 at 20:08
  • No worries at all. I just wanted to clarify for anyone else that searches this board. Thanks again! – Thomas Linton Mar 26 '17 at 22:00
1

If I understand correctly. You have an object formatted like this:

datas = {fieldA:[{raw_date:0}, {raw_date:1}], fieldB[{raw_date:0}, {raw_date:1}]};

And you want to convert it to an array formatted like this:

datas = [{fieldA:{raw_date:0, raw_date:1}, {fieldB{raw_date:0, raw_date:1}}];

If that is the case, you can do something like this:

var org = {fieldA:[{raw_data:0}, {raw_data:1}], fieldB:[{raw_data:0}, {raw_data:1}]};

var reformatted = [];
for(var i = 0; i < Math.min(org.fieldA.length, org.fieldB.length); i++){  
  reformatted.push({filedA:{raw_data:org.fieldA[i].raw_data}, fieldB:{raw_data:org.fieldB[i].raw_data}});
}

console.log(reformatted);
Titus
  • 22,031
  • 1
  • 23
  • 33
-1
var datas= {
    fieldA: [1, 2, 3],
    filedB: [4, 5, 6]
};

var array = $.map(datas, function(value, index) {
    return [value];
});
Bimal Das
  • 1,882
  • 5
  • 28
  • 53
jp rathore
  • 35
  • 10