简体   繁体   中英

D3 graph with slider need too change color of outside nodes

I have a D3 script that creates a graph that has a slider on the side. This slider will only display link nodes that have a degree indicated by the slider. All other nodes will be disconnected and off to the side.

Currently, this code displays all nodes the same color. I would like the ability to make the nodes on the outside a different color (ie gray) to distinguish better from the ones that are connected.

I imagine it shouldn't be too difficult. In the brushed function it checks the threshold to the nodes degrees and removes the links. maybe if degree < threshold, color = gray. or check the link? I can't see to make it work.

If ( "no links" )
      node.append("circle")
      .attr("r", 5)
      .style("fill", "gray")

Any assistance would be welcome!

My script below

<!DOCTYPE html>
<meta charset="utf-8">
<title>Slider Graph 2</title>
<style>

.node {
  stroke: #fff;
  stroke-width: 1.5px;
}

.link {
  stroke: #999;
  stroke-opacity: .6;
}

.axis {
  opacity: 0.5;
  font: 10px sans-serif;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
}

.axis .domain {
  fill: none;
  stroke: #000;
  stroke-opacity: .3;
  stroke-width: 4px;
  stroke-linecap: round;
}

.axis .halo {
  fill: none;
  stroke: #ddd;
  stroke-width: 3px;
  stroke-linecap: round;
}

text {
  pointer-events: none;
  font: 10px sans-serif;
  stroke: none;
  fill: gray;

}


.slider .handle {
  fill: #fff;
  stroke: #000;
  stroke-opacity: .5;
  stroke-width: 1.25px;
  cursor: grab;
}

</style>
<body>
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <script>

    var width = 1000,
    height = 700;

    var color = d3.scale.category20();

    var force = d3.layout.force()
    .charge(-150)
    .linkDistance(60)
    .size([width, height]);

// gets largest degree for slider
d3.json("test4.json", function(error, graph) {
  if (error) throw error;
  var g = 0

  graph.nodes.forEach(function(d,i){
    if (d.degree > g){
      g = d.degree;

    }

  });
  console.log(g); 
  var x = d3.scale.linear()
  .domain([0, g+2])
  .range([250, 80])
  .clamp(true);



  var brush = d3.svg.brush()
  .y(x)
  .extent([0, 0]);

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

  var links_g = svg.append("g");

  var nodes_g = svg.append("g");

  svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(" + (width - 20)  + ",0)")
  .call(d3.svg.axis()
    .scale(x)
    .orient("left")
    .tickFormat(function(d) { return d; })
    .tickSize(0)
    .tickPadding(12))
  .select(".domain")
  .select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
  .attr("class", "halo");

  var slider = svg.append("g")
  .attr("class", "slider")
  .call(brush);

  slider.selectAll(".extent,.resize")
  .remove();

  var handle = slider.append("circle")
  .attr("class", "handle")
  .attr("transform", "translate(" + (width - 20) + ",0)")
  .attr("r", 5);

  svg.append("text")
  .attr("x", width - 15)
  .attr("y", 60)
  .attr("text-anchor", "end")
  .attr("font-size", "12px")
  .style("opacity", 0.5)
  .text("degree threshold")


//Get file
d3.json("test4.json", function(error, graph) {
  if (error) throw error;
  

  graph.links.forEach(function(d,i){ d.i = i; });
  graph.nodes.forEach(function(d,i){ d.i = i; });

  function brushed() {
    var value = brush.extent()[0];

    if (d3.event.sourceEvent) {
      value = x.invert(d3.mouse(this)[1]);
      brush.extent([value, value]);
    }
    handle.attr("cy", x(value));
    var threshold = value;
    console.log(graph.nodes);
    var thresholded_nodes = graph.nodes.filter(function(d){ return (d.degree > threshold);});
    var thresholded_links = graph.links.filter(function(d){ return (d.min_degree > threshold);});
    console.log(thresholded_nodes);

 //     node.append("circle")
  //    .attr("r", 5)
  //    .style("fill", "red")
  //  force
  //  .links(thresholded_links);

    var link = links_g.selectAll(".link")
    .data(thresholded_links, function(d){ return d.i; });

    link.enter().append("line")
    .attr("class", "link")
    .style("stroke-width", function(d) { return Math.sqrt(d.value); });

    link.exit().remove();


    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("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });

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

    force.start();

  }

  force
  .nodes(graph.nodes);


  var node = nodes_g.selectAll(".node")
  .data(graph.nodes)
  .enter()
  .append('g')
  .attr("class", "node")
  .call(force.drag);
  
  node.append("circle")
  .attr("r", 5)
  // .style("fill", function(d) { return color(1); })
  .style("fill", function(d) {
    return color(1);
  })
  
  node.append("text")
  .attr("dy", ".35em")
  .text(function(d) { return d.name });

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


  // var node = nodes_g.selectAll(".node")
  // .data(graph.nodes)
  // .enter().append("circle")
  // .attr("class", "node")
  // .attr("r", 5)
  //     // .style("fill", function(d) { return color(1); })
  //     .style("fill", function(d) { return color(1); })
  //     .call(force.drag);
      // node.append("title")
      // .attr("dx", function(d){return -20})
      // .text(function(d) { return d.name; });

      brush.on("brush", brushed);

      slider
      .call(brush.extent([5, 5]))
      .call(brush.event);

    });
});

</script>

Link to test data

EDIT: It should be checking the link's Min degree, and if that is less than the threshold, both nodes in the link should be gray.

This is D3 v3. In that version, there is a property named weight , which indicates if a node has links:

According to the API :

weight - the node weight; the number of associated links.

So, you just need:

node.each(function(d) {
    d3.select(this).select("circle")
    .style("fill", d.weight ? color(1) : "#ccc")
  })

Here is your code with that change:

 var jobject = `{"nodes":[ {"name":"ADH1A","degree":9}, {"name":"ADH1B","degree":10}, {"name":"ADH1C","degree":9}, {"name":"ADH4","degree":10}, {"name":"ADH5","degree":9}, {"name":"ADH7","degree":9}, {"name":"ALDH1A1","degree":11}, {"name":"ALDH2","degree":9}, {"name":"BDNF","degree":5}, {"name":"CHRNA5","degree":1}, {"name":"CHRNB4","degree":2}, {"name":"CNR1","degree":1}, {"name":"COMT","degree":13}, {"name":"CRHR1","degree":1}, {"name":"CYP2E1","degree":9}, {"name":"DRD1","degree":7}, {"name":"DRD2","degree":9}, {"name":"DRD3","degree":4}, {"name":"DRD4","degree":6}, {"name":"GABRA1","degree":9}, {"name":"GABRA2","degree":8}, {"name":"GABRA6","degree":7}, {"name":"GABRB1","degree":8}, {"name":"GABRB2","degree":8}, {"name":"GABRB3","degree":7}, {"name":"GABRG1","degree":5}, {"name":"GABRG2","degree":8}, {"name":"GAL","degree":5}, {"name":"GRIK3","degree":1}, {"name":"GRIN2B","degree":3}, {"name":"GRM8","degree":4}, {"name":"HTR1A","degree":2}, {"name":"HTR1B","degree":5}, {"name":"HTR2A","degree":5}, {"name":"MAOA","degree":17}, {"name":"NPY","degree":7}, {"name":"OPRD1","degree":4}, {"name":"OPRK1","degree":6}, {"name":"OPRM1","degree":3}, {"name":"PDYN","degree":6}, {"name":"POMC","degree":10}, {"name":"SLC6A3","degree":8}, {"name":"SLC6A4","degree":13}, {"name":"TPH1","degree":3} ], "links":[ {"source":0,"target":1,"min_degree":9}, {"source":0,"target":2,"min_degree":9}, {"source":0,"target":3,"min_degree":9}, {"source":0,"target":4,"min_degree":9}, {"source":0,"target":5,"min_degree":9}, {"source":0,"target":6,"min_degree":9}, {"source":0,"target":7,"min_degree":9}, {"source":0,"target":8,"min_degree":9}, {"source":0,"target":11,"min_degree":9}, {"source":1,"target":2,"min_degree":9}, {"source":1,"target":3,"min_degree":10}, {"source":1,"target":4,"min_degree":9}, {"source":1,"target":5,"min_degree":9}, {"source":1,"target":6,"min_degree":10}, {"source":1,"target":7,"min_degree":10}, {"source":1,"target":8,"min_degree":9}, {"source":1,"target":9,"min_degree":9}, {"source":1,"target":11,"min_degree":10}, {"source":2,"target":3,"min_degree":9}, {"source":2,"target":4,"min_degree":9}, {"source":2,"target":5,"min_degree":9}, {"source":2,"target":6,"min_degree":9}, {"source":2,"target":8,"min_degree":9}, {"source":2,"target":9,"min_degree":9}, {"source":2,"target":11,"min_degree":9}, {"source":3,"target":4,"min_degree":9}, {"source":3,"target":5,"min_degree":9}, {"source":3,"target":6,"min_degree":10}, {"source":3,"target":7,"min_degree":10}, {"source":3,"target":8,"min_degree":9}, {"source":3,"target":9,"min_degree":9}, {"source":3,"target":11,"min_degree":10}, {"source":4,"target":5,"min_degree":9}, {"source":4,"target":6,"min_degree":9}, {"source":4,"target":8,"min_degree":9}, {"source":4,"target":9,"min_degree":9}, {"source":4,"target":11,"min_degree":9}, {"source":5,"target":6,"min_degree":9}, {"source":5,"target":8,"min_degree":9}, {"source":5,"target":9,"min_degree":9}, {"source":5,"target":11,"min_degree":9}, {"source":6,"target":8,"min_degree":9}, {"source":6,"target":9,"min_degree":9}, {"source":6,"target":10,"min_degree":9}, {"source":6,"target":11,"min_degree":11}, {"source":6,"target":24,"min_degree":10}, {"source":7,"target":8,"min_degree":9}, {"source":7,"target":9,"min_degree":9}, {"source":7,"target":11,"min_degree":13}, {"source":7,"target":13,"min_degree":7}, {"source":7,"target":18,"min_degree":2}, {"source":7,"target":21,"min_degree":2}, {"source":7,"target":23,"min_degree":7}, {"source":7,"target":25,"min_degree":8}, {"source":7,"target":39,"min_degree":6}, {"source":7,"target":41,"min_degree":6}, {"source":8,"target":9,"min_degree":9}, {"source":9,"target":11,"min_degree":9}, {"source":10,"target":12,"min_degree":5}, {"source":10,"target":15,"min_degree":6}, {"source":10,"target":22,"min_degree":5}, {"source":10,"target":23,"min_degree":7}, {"source":10,"target":24,"min_degree":9}, {"source":10,"target":25,"min_degree":8}, {"source":10,"target":39,"min_degree":6}, {"source":10,"target":41,"min_degree":6}, {"source":11,"target":13,"min_degree":7}, {"source":11,"target":20,"min_degree":5}, {"source":11,"target":23,"min_degree":7}, {"source":11,"target":25,"min_degree":8}, {"source":11,"target":34,"min_degree":13}, {"source":11,"target":37,"min_degree":5}, {"source":11,"target":39,"min_degree":6}, {"source":11,"target":41,"min_degree":6}, {"source":12,"target":13,"min_degree":5}, {"source":12,"target":14,"min_degree":4}, {"source":12,"target":15,"min_degree":5}, {"source":12,"target":16,"min_degree":4}, {"source":13,"target":22,"min_degree":5}, {"source":13,"target":23,"min_degree":7}, {"source":13,"target":24,"min_degree":7}, {"source":13,"target":25,"min_degree":7}, {"source":14,"target":22,"min_degree":4}, {"source":14,"target":23,"min_degree":4}, {"source":14,"target":24,"min_degree":4}, {"source":15,"target":22,"min_degree":5}, {"source":15,"target":23,"min_degree":6}, {"source":15,"target":24,"min_degree":6}, {"source":15,"target":26,"min_degree":6}, {"source":16,"target":22,"min_degree":4}, {"source":16,"target":23,"min_degree":4}, {"source":16,"target":24,"min_degree":4}, {"source":17,"target":18,"min_degree":1}, {"source":19,"target":20,"min_degree":1}, {"source":20,"target":25,"min_degree":5}, {"source":20,"target":34,"min_degree":5}, {"source":20,"target":43,"min_degree":3}, {"source":21,"target":37,"min_degree":2}, {"source":24,"target":38,"min_degree":4}, {"source":24,"target":39,"min_degree":6}, {"source":24,"target":40,"min_degree":3}, {"source":24,"target":42,"min_degree":1}, {"source":25,"target":34,"min_degree":8}, {"source":25,"target":36,"min_degree":3}, {"source":25,"target":37,"min_degree":5}, {"source":26,"target":27,"min_degree":8}, {"source":26,"target":28,"min_degree":7}, {"source":26,"target":29,"min_degree":8}, {"source":26,"target":30,"min_degree":8}, {"source":26,"target":31,"min_degree":7}, {"source":26,"target":32,"min_degree":5}, {"source":26,"target":33,"min_degree":8}, {"source":26,"target":34,"min_degree":9}, {"source":27,"target":28,"min_degree":7}, {"source":27,"target":29,"min_degree":8}, {"source":27,"target":30,"min_degree":8}, {"source":27,"target":31,"min_degree":7}, {"source":27,"target":32,"min_degree":5}, {"source":27,"target":33,"min_degree":8}, {"source":27,"target":34,"min_degree":8}, {"source":28,"target":29,"min_degree":7}, {"source":28,"target":30,"min_degree":7}, {"source":28,"target":31,"min_degree":7}, {"source":28,"target":33,"min_degree":7}, {"source":28,"target":34,"min_degree":7}, {"source":29,"target":30,"min_degree":8}, {"source":29,"target":31,"min_degree":7}, {"source":29,"target":32,"min_degree":5}, {"source":29,"target":33,"min_degree":8}, {"source":29,"target":34,"min_degree":8}, {"source":30,"target":31,"min_degree":7}, {"source":30,"target":32,"min_degree":5}, {"source":30,"target":33,"min_degree":8}, {"source":30,"target":34,"min_degree":8}, {"source":31,"target":33,"min_degree":7}, {"source":31,"target":34,"min_degree":7}, {"source":32,"target":33,"min_degree":5}, {"source":33,"target":34,"min_degree":8}, {"source":34,"target":36,"min_degree":3}, {"source":34,"target":37,"min_degree":5}, {"source":34,"target":43,"min_degree":3}, {"source":35,"target":36,"min_degree":1}, {"source":37,"target":43,"min_degree":3}, {"source":38,"target":39,"min_degree":4}, {"source":38,"target":40,"min_degree":3}, {"source":38,"target":41,"min_degree":4}, {"source":39,"target":41,"min_degree":6}, {"source":40,"target":41,"min_degree":3} ]}` var graph = JSON.parse(jobject); var width = 960, height = 500; var color = d3.scale.category20(); var force = d3.layout.force() .charge(-120) .linkDistance(30) .size([width, height]); var x = d3.scale.linear() .domain([0, 20]) .range([250, 80]) .clamp(true); var brush = d3.svg.brush() .y(x) .extent([0, 0]); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var links_g = svg.append("g"); var nodes_g = svg.append("g"); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(" + (width - 20) + ",0)") .call(d3.svg.axis() .scale(x) .orient("left") .tickFormat(function(d) { return d; }) .tickSize(0) .tickPadding(12)) .select(".domain") .select(function() { return this.parentNode.appendChild(this.cloneNode(true)); }) .attr("class", "halo"); var slider = svg.append("g") .attr("class", "slider") .call(brush); slider.selectAll(".extent,.resize") .remove(); var handle = slider.append("circle") .attr("class", "handle") .attr("transform", "translate(" + (width - 20) + ",0)") .attr("r", 5); svg.append("text") .attr("x", width - 15) .attr("y", 60) .attr("text-anchor", "end") .attr("font-size", "12px") .style("opacity", 0.5) .text("degree threshold") graph.links.forEach(function(d, i) { di = i; }); graph.nodes.forEach(function(d, i) { di = i; }); function brushed() { var value = brush.extent()[0]; if (d3.event.sourceEvent) { value = x.invert(d3.mouse(this)[1]); brush.extent([value, value]); } handle.attr("cy", x(value)); var threshold = value; var thresholded_nodes = graph.nodes.filter(function(d) { return (d.degree > threshold); }); var thresholded_links = graph.links.filter(function(d) { return (d.min_degree > threshold); }); force .links(thresholded_links); var link = links_g.selectAll(".link") .data(thresholded_links, function(d) { return di; }); link.enter().append("line") .attr("class", "link") .style("stroke-width", function(d) { return Math.sqrt(d.value); }); link.exit().remove(); 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(" + dx + "," + dy + ")"; }); }); force.start(); node.each(function(d) { d3.select(this).select("circle").style("fill", d.weight ? color(1) : "#ccc") }) } force .nodes(graph.nodes); var node = nodes_g.selectAll(".node") .data(graph.nodes) .enter() .append('g') .attr("class", "node") .call(force.drag); node.append("circle") .attr("r", 5) // .style("fill", function(d) { return color(1); }) .style("fill", function(d) { return color(1); }) node.append("text") .attr("dx", 4) .attr("dy", ".35em") .text(function(d) { return d.name }); node.append("title") .text(function(d) { return d.name; }); brush.on("brush", brushed); slider .call(brush.extent([5, 5])) .call(brush.event);
 .node { stroke: #fff; stroke-width: 1.5px; } .link { stroke: #999; stroke-opacity: .6; } .axis { opacity: 0.5; font: 10px sans-serif; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .axis .domain { fill: none; stroke: #000; stroke-opacity: .3; stroke-width: 4px; stroke-linecap: round; } .axis .halo { fill: none; stroke: #ddd; stroke-width: 3px; stroke-linecap: round; } text { pointer-events: none; font: 8px sans-serif; stroke: none; fill: red; } .slider .handle { fill: #fff; stroke: #000; stroke-opacity: .5; stroke-width: 1.25px; cursor: grab; }
 <script src="https://d3js.org/d3.v3.min.js"></script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM