1

I need to set the radius of some circles, i have the following data, made up of links and nodes. I need to set the radius of the circles(nodes), to the sum of the links connected to the nodes

var data = {
    "nodes": [
        {
            "id": "s1",
            "val": 12
        },
        {
            "id": "s2",
            "val": 12
        },
        {
            "id": "s3",
            "val": 12
        },
        {
            "id": "s4",
            "val": 12
        },
        {
            "id": "s5",
            "val": 12
        },
        {
            "id": "s6",
            "val": 12
        }
    ],
    "Links": [
        {
            "n1": "s1",
            "n2": "s2",
            "amount": 10
        },
        {
            "n1": "s2",
            "n2": "s3",
            "amount": 10
        },
        {
            "n1": "s2",
            "n2": "s4",
            "amount": 10
        },
        {
            "n1": "s2",
            "n2": "s6",
            "amount": 10
        },
        {
            "n1": "s3",
            "n2": "s1",
            "amount": 10
        },
        {
            "n1": "s4",
            "n2": "s5",
            "amount": 10
        },
        {
            "n1": "s5",
            "n2": "s6",
            "amount": 10
        }
    ]
};

i.e. ( i expect the node to be in context at this point), i have written some pseudo code below

val1 = 0
val2 = 0 
for i to len.links
  if (links.node1 = nodes.id)
    val1 = val1 + links.amount
  else if (links.node02 = nodes.id)
    val2 = val2 + links.amount
next
sum = val1 + val2

The code below, puts the circles to the screen, i have tried various methods but allays results in what i am referring to as the white screen of death

  var w = 1200;
  var h = 800;
  var svg = d3.select("body").append("svg").attr("width",w).attr("height", h);
      var lines = svg.attr("class", "line")
  d3.json("data.json", function(error, data) {
        console.log(data);

        var circles = svg.selectAll("foo")
  .data(data.nodes)
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return d.x;
  })
  .attr("cy", function(d) {
    return d.y;
  })
  .attr("r", 20); // <- i want to put this calculation here

I am new to JS and have no idea how to translate this in to Javascript

1 Answer 1

1

I felt like this would take too long to explain without typing it out as d3 can be confusing, and js on its own... well anyways. I hacked this together in a jsbin and added some comments. You should be able to follow through line by line and figure out what's going on. Google the syntax if you don't understand or leave a comment and I'll try and help you reason through it.

jsbin with working example

const data = {
  "nodes": [
      {
          "id": "s1",
          "val": 12
      },
      {
          "id": "s2",
          "val": 12
      },
      {
          "id": "s3",
          "val": 12
      },
      {
          "id": "s4",
          "val": 12
      },
      {
          "id": "s5",
          "val": 12
      },
      {
          "id": "s6",
          "val": 12
      }
  ],
  "links": [
      {
          "n1": "s1",
          "n2": "s2",
          "amount": 10
      },
      {
          "n1": "s2",
          "n2": "s3",
          "amount": 10
      },
      {
          "n1": "s2",
          "n2": "s4",
          "amount": 10
      },
      {
          "n1": "s2",
          "n2": "s6",
          "amount": 10
      },
      {
          "n1": "s3",
          "n2": "s1",
          "amount": 10
      },
      {
          "n1": "s4",
          "n2": "s5",
          "amount": 10
      },
      {
          "n1": "s5",
          "n2": "s6",
          "amount": 10
      }
  ]
};


const width = window.innerWidth;
const height = window.innerHeight;
//set up the svg container
const svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
.style('background-color', 'lightgray'); // just to see the outline

//update our data to have referable x, y positions for each node
data.nodes.forEach(n => { 
  n.x = Math.random()*width; //since I don't know how you want them arranged...
  n.y = Math.random()*height;//...i'm setting them randomly
})

//draw the lines
//each line has an x1,y1 and an x2,y2
//again not sure how you wanted them connected...
//so just doing the obvious based on the link info
const lines = svg.selectAll('line')
.data(data.links)
.enter()
.append('line')
.attr('stroke', 'black')
.attr('x1', l => {
  let node = data.nodes.filter(n => n.id === l.n1)[0];
  return node.x;
})
.attr('y1', l => {
  let node = data.nodes.filter(n => n.id === l.n1)[0];
  return node.y;
})
.attr('x2', l => {
  let node = data.nodes.filter(n => n.id === l.n2)[0];
  return node.x;
})
.attr('y2', l => {
  let node = data.nodes.filter(n => n.id === l.n2)[0];
  return node.y;
})
//draw the circles
const circles = svg.selectAll('circle')
.data(data.nodes)
.enter()
.append('circle')
// basically just random colors
.attr('fill', () => d3.color('#'+Math.floor(Math.random() * Math.pow(2,32) ^ 0xffffff).toString(16).substr(-6)))
.attr('cx', n => n.x)
.attr('cy', n => n.y)
.attr('r', n => {
  //for each node, first i find all the links that contain...
  //either n1 or n2 that matches the node's id
  let rels = data.links.filter(l => n.id === l.n1 || n.id === l.n2);
  //just google the reduce fn... it'll be easier...
  let sum = rels.reduce((a,b) => a + b.amount,0);
  return sum;
});
//add labels so we know whats what
const labels = svg.selectAll('text')
.data(data.nodes)
.enter()
.append('text')
.attr('x', n => n.x)
.attr('y', n => n.y)
.attr('text-anchor', 'middle') //horizontal align
.attr('alignment-baseline', 'central') //vertical align
.text(n => n.id)

Try updating the amounts in your links to see a dynamic update / resizing!

Sign up to request clarification or add additional context in comments.

2 Comments

One thing to note, that the d3 enter syntax is not the customary way to iterate over JSON data. It is just the d3 way. As such, your title isn't very accurate. Your real question is "how to leverage js library, d3, to render based on data"
That worked perfectly. I cant believe it was this simple

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.