JS- how to remove duplicate JSON nodes and add one link for all nodes that get merged

Viewed 186

enter code here I have a JSON File from which I want to create a d3 directed graph with arrows in the direction of higher influence score

{"nodes":[{"Name":"GJA","influenceScore":81.0,"type":10.0},
{"Name":"JJZ","influenceScore":82.6,"type":30.0},
{"Name":"SAG","influenceScore":89.0,"type":30.0},
{"Name":"JJZ","influenceScore":82.6,"type":30.0}],"links":
[{"source":0,"target":0,"type":"SA","value":1},
{"source":0,"target":1,"type":"SA","value":1},
{"source":0,"target":2,"type":"SA","value":1},
{"source":0,"target":3,"type":"SA","value":1}]}

I am a d3novice, so would like some help from experts here My d3 code is here:

.link {
 stroke: #ccc;
 }

.node text {
 pointer-events: none;
 font: 12px sans-serif;
 }

</style>


<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 1200,
    height = 900;

var color = d3.scale.category10();
var fill = d3.scale.category10();
var svg = d3.select("body").append("svg")
   .attr("width", width)
   .attr("height", height);

var force = d3.layout.force()
   .gravity(0.052)
   .distance(350)
   .charge(-20)
   .size([width, height]);

d3.json("\\abc.json", function(error, json) {
 if (error) throw error;

 force
  .nodes(json.nodes)
  .links(json.links)
  .start();

var link = svg.selectAll(".link")
   .data(json.links)
   .enter().append("line")
   .attr("class", "link").style("stroke-width", function(d) { return 
    Math.sqrt(d.value); }).style("stroke", function(d) {return 
    fill(d.value);});

var node = svg.selectAll(".node")
  .data(json.nodes)
 .enter().append("g")
  .attr("class", "node")
  .call(force.drag);

  node.append("circle")
  .attr("class", "node")
  .attr("r", function(d) { return (d.influenceScore/10) + 10; 
  }).style("fill", function(d) { return color(d.type); });

  node.append("text")
  .attr("dx", -35)
  .attr("dy", "4.5em").text(function(d) { return d.Name });


  node.append("title").text(function(d) { return d.Name ;});


 force.on("tick", function() {
  link.attr("x1", function(d) { return d.source.x; })
    .attr("y1", function(d) { return d.source.y; })
    .attr("x2", function(d) { return d.target.x; })
    .attr("y2", function(d) { return d.target.y; });

node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + 
 ")"; });
   });
  });

I am getting the following image enter image description here

I would like the target node e.g JJZ here just to occur once ( currently it's occurring as many number of times as it is repeated in the JSON i.e 2 times in the given example) however the line joining the two nodes should increase in thickness depending on the number of times the nodes repeat. so the blue line linking JJZ with GJA should be thicker than GJA and SAG and if another node occurs 5 times that should be thicker than JJZ and GJA. Also how do I insert directed arrows in the direction of a higher influence score

1 Answers

Your question here has little to do with D3: you can manipulate your array with plain JavaScript.

This function looks for the objects on json.nodes based on the property Name. If it doesn't exist, it pushes the object into an array that I named filtered. If it already exists, it increases the value of count in that object:

var filtered = []

json.nodes.forEach(function(d) {
  if (!this[d.Name]) {
    d.count = 0;
    this[d.Name] = d;
    filtered.push(this[d.Name])
  }
  this[d.Name].count += 1
}, Object.create(null))

Here is the demo:

var json = {"nodes":[{"Name":"GJA","influenceScore":81.0,"type":10.0},
{"Name":"JJZ","influenceScore":82.6,"type":30.0},
{"Name":"SAG","influenceScore":89.0,"type":30.0},
{"Name":"JJZ","influenceScore":82.6,"type":30.0}],"links":
[{"source":0,"target":0,"type":"SA","value":1},
{"source":0,"target":1,"type":"SA","value":1},
{"source":0,"target":2,"type":"SA","value":1},
{"source":0,"target":3,"type":"SA","value":1}]};

var filtered = []

json.nodes.forEach(function(d){
 if(!this[d.Name]){
   d.count = 0;
   this[d.Name] = d;
    filtered.push(this[d.Name])
  }
  this[d.Name].count += 1
}, Object.create(null))

console.log(filtered)

Then, you just need to use the property count to set the stroke-width of your links.

Related