plunkerでd3 その9


概要

plunkerでd3やってみた。
山形県のデータ、読んでみた。
forceSimulationでクラスターを表現してみた。

写真

サンプルコード

d3.json("https://raw.githubusercontent.com/yamaserif/covid19/development/data/data.json", function(error, data) {
  var patients = data.patients.data;
  var keys = ["リリース日", "居住地", "年代", "性別", "退院", "date"];
  var table = d3.select("body").append("table").attr("border", "1")
  table.append("thead").append("tr").selectAll("th").data(keys).enter().append("th").text(function(d) {
    return d;
  });
  patients.unshift({
    "リリース日": null,   
    "居住地": "クラスター", 
    "年代": "特養", 
    "性別": "", 
    "退院": null, 
    "date": null
  });
  patients.unshift({
    "リリース日": null,   
    "居住地": "クラスター", 
    "年代": "佐勇", 
    "性別": "", 
    "退院": null, 
    "date": null
  }); 
  patients.unshift({
    "リリース日": null,   
    "居住地": "クラスター", 
    "年代": "仙台HUB", 
    "性別": "", 
    "退院": null, 
    "date": null
  });
  patients.unshift({
    "リリース日": null,   
    "居住地": "クラスター", 
    "年代": "友人", 
    "性別": "", 
    "退院": null, 
    "date": null
  });
  patients.unshift({
    "リリース日": null,   
    "居住地": "クラスター", 
    "年代": "家庭内", 
    "性別": "", 
    "退院": null, 
    "date": null
  });
  for (var i = 0; i < patients.length; i++)
  {
    var rows = [];  
    keys.map(function(c) {
      rows.push(patients[i][c])
    });
    rows[4] = i;
    table.append("tbody").append("tr").selectAll("td").data(rows).enter().append("td").text(function(d) {
      return d;
    });
  }
  var node = [];
  var link = [{ 
    "source": 0, 
    "target": 8
  }, {
    "source": 0,
    "target": 9
  }, {
    "source": 0,
    "target": 10
  }, {
    "source": 0, 
    "target": 57
  }, { 
    "source": 0, 
    "target": 11
  }, {
    "source": 0,
    "target": 12
  }, {
    "source": 0,
    "target": 13
  }, {
    "source": 10, 
    "target": 4 
  }, { 
    "source": 4, 
    "target": 55
  }, {
    "source": 4,
    "target": 14 
  }, {
    "source": 4,
    "target": 55
  }, {
    "source": 4, 
    "target": 56 
  }, { 
    "source": 4, 
    "target": 42
  }, {
    "source": 4,
    "target": 44 
  }, {
    "source": 4,
    "target": 47
  }, {
    "source": 14, 
    "target": 45
  }, { 
    "source": 14, 
    "target": 64
  }, {
    "source": 14,
    "target": 67
  }, {
    "source": 42,
    "target": 46
  }, {
    "source": 44, 
    "target": 60 
  }, { 
    "source": 44, 
    "target": 62
  }, {
    "source": 44,
    "target": 63
  }, {
    "source": 4,
    "target": 70
  }, {
    "source": 2, 
    "target": 18 
  }, { 
    "source": 2, 
    "target": 23
  }, {
    "source": 18,
    "target": 28
  }, {
    "source": 23,
    "target": 25
  }, {
    "source": 23, 
    "target": 26
  }, { 
    "source": 27, 
    "target": 36
  }, {
    "source": 27,
    "target": 37
  }, {
    "source": 32,
    "target": 43
  }, {
    "source": 43, 
    "target": 48
  }, { 
    "source": 1, 
    "target": 21
  }, {
    "source": 1,
    "target": 15 
  }, {
    "source": 1,
    "target": 17
  }, {
    "source": 1, 
    "target": 18 
  }, { 
    "source": 21, 
    "target": 3
  }, {
    "source": 15,
    "target": 22
  }, {
    "source": 15,
    "target": 16
  }, {
    "source": 15, 
    "target": 39
  }, { 
    "source": 19, 
    "target": 29
  }, {
    "source": 19,
    "target": 30
  }, {
    "source": 19,
    "target": 31
  }, {
    "source": 29, 
    "target": 38
  }, { 
    "source": 3, 
    "target": 33
  }, {
    "source": 3,
    "target": 34 
  }, {
    "source": 3,
    "target": 35
  }, {
    "source": 3, 
    "target": 41
  }, {
    "source": 3,
    "target": 49 
  }, {
    "source": 3,
    "target": 50
  }, {
    "source": 3, 
    "target": 51 
  }, { 
    "source": 3, 
    "target": 54
  }, {
    "source": 3,
    "target": 53 
  }, {
    "source": 3,
    "target": 68
  }, {
    "source": 49, 
    "target": 58
  }, {
    "source": 49,
    "target": 59
  }, {
    "source": 53,
    "target": 65
  }, {
    "source": 68, 
    "target": 66
  }];
  for (i = 0; i < patients.length; i++)
  {
    node.push({
      id: patients[i]['居住地'] + patients[i]['年代'] + patients[i]['性別']
    });
  }
  process_network(node, link);
});

function process_network(nodesData, linksData) {
  var link = d3.select("svg").selectAll("line").data(linksData).enter().append("line").attr("stroke-width", 1).attr("stroke", "black");
  var node = d3.select("svg").selectAll("g").data(nodesData).enter().append("g").call(d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended));
  node.append("circle").attr("r", 10).attr("stroke", "black").attr("stroke-width", 1.5).attr("fill", "peachpuff");
  node.append("text").attr("text-anchor", "middle").attr("dominant-baseline", "middle").style("fill", "gray").text(function(d) {
    return d.id;
  }).append("title").text(function(d) {
    return d.id;
  });
  var simulation = d3.forceSimulation(nodesData).velocityDecay(0.3).alpha(0.7)
    .force("link", d3.forceLink().distance(120))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(200, 200));
  simulation.nodes(nodesData).on("tick", ticked);
  simulation.force("link").links(linksData);
  function ticked() {
    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.select("circle").attr("cx", function(d) {
      return d.x;
    }).attr("cy", function(d) {
      return d.y;
    });
    node.select("text").attr("dx", function(d) {
      return d.x;
    }).attr("dy", function(d) {
      return d.y + 40;
    });
  }
  function dragstarted(d) {
    if (!d3.event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
  }
  function dragged(d) {
    d.fx = d3.event.x;
    d.fy = d3.event.y;
  }
  function dragended(d) {
    if (!d3.event.active) simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  }
}




成果物

以上。