Upgrade to Pro — share decks privately, control downloads, hide ads and more …

d3.js demonstration

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

d3.js demonstration

Avatar for muddydixon

muddydixon

March 28, 2023
Tweet

More Decks by muddydixon

Other Decks in Programming

Transcript

  1. σʔλՄࢹԽͱ͸ The main goal of data visualization is its ability

    to visualize data, communicating information clearly and effectivelty. Vitaly Friedman $ σʔλՄࢹԽͷ໨త͸ɺσʔλΛՄࢹԽ͠ɺ ৘ใΛ໌͔֬ͭޮ཰తʹ఻͑Δ͜ͱͰ͋Δ $
  2. %KTͱ͸d%%%d <      > < 

        > 正規化 図形化
  3. %KTͱ͸d%%%d <      > < 

        > 正規化 図形化 %BUB%SJWFO %PDVNFOUT
  4. %KTͱ͸d%%%d  4FQBM-FOHUI 4FQBM8JEUI 1FUBM-FOHUI 1FUBM8JEUI 4QFDJFT   

      TFUPTB      TFUPTB      TFUPTB      TFUPTB      TFUPTB      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB
  5. %KTͱ͸d%%%d  4FQBM-FOHUI 4FQBM8JEUI 1FUBM-FOHUI 1FUBM8JEUI 4QFDJFT   

      TFUPTB      TFUPTB      TFUPTB      TFUPTB      TFUPTB      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB
  6. %KTͱ͸d%%%d  4FQBM-FOHUI 4FQBM8JEUI 1FUBM-FOHUI 1FUBM8JEUI 4QFDJFT   

      TFUPTB      TFUPTB      TFUPTB      TFUPTB      TFUPTB      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WFSTJDPMPS      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB      WJSHJOJDB %BUB%SJWFO %PDVNFOUT
  7. %KTͷྲྀΕ)5.- جຊ͸͜ΕͰͣͬͱ͍͖·͢ <!doctype html> <html> <head> <meta charset="utf-8"> <title>D3.js on

    GTUG Girls Tokyo</title> <style> .axis path, .axis line { fill: none; stroke: grey; } </style> </head> <body> <script type="text/javascript" src="//code.jquery.com/jquery-2.1.1.min.js"></script> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/ d3.min.js"></script> <script type="text/javascript" src="./src/main.js"></script> </body> </html>
  8. %KTͷྲྀΕ8FC 8FC্͓͛ͯ͘ͱ"KBYͱ͔΋࢖͑ͯศརͰ͢ python -m http.server 5000 python -m SimpleHTTPServer 5000

    plackup -MPlack::App::Directory -e 'Plack::App::Directory->new(root => ".")->to_app' ruby -run -e httpd -- --port=5000 . ruby -rwebrick -e 'WEBrick::HTTPServer.new(:Port => 5000, :DocumentRoot => ".").start' http://blog.kamipo.net/entry/2013/02/20/122225
  9. %KTͷྲྀΕσʔλ σʔλΛ࡞Γ·͢ ͜͏͍͏ͷ࡞͓ͬͯ͘ͱศར // データ生成ユーティリティ var dataGenerator = function(len, gen){

    var array = [], i = 0; for(i = 0; i < len; i++){ array.push(gen ? gen(i) : i); } return array; }; // データ生成 var data = dataGenerator(100, function(i){ return { id: i, name: "name "+ i, x: 0|Math.random() * width, y: 0|Math.random() * height }; });
  10. %KTͷྲྀΕ47( ౔୆ TWH ࡞Γ // var svg = d3.select("body").append("svg") .attr({width:

    WIDTH, height: HEIGHT}); var main = svg.append("g") .attr({ width: width, height: height, transform: “translate("+margin+","+margin+")" }); 初出 * (selection) d3.select * (selection) selection.append * (selection) selection.attr
  11. %KTͷྲྀΕσʔλͱ%0.ͷඥ෇͚ σʔλͷඥ෇͚ var circle = // 現状の取得 main.selectAll("g.circle") // データのヒモ付

    .data(data) // データ > 現状(DOM)の部分を取得 .enter() // "g"要素を追加し、classをセット .append("g").attr({"class": "circle"}); 初出 * (selection) selection.selectAll * (selection) selection.data * (selection) selection.enter
  12. %KTͷྲྀΕDPMPS ৭Λऔಘͯ͠ΈΑ͏ var color = d3.scale.category20(); circle.append("circle").attr({ r: 10, cx:

    function(d){ return d.x; }, cy: function(d){ return d.y; }, fill: function(d, i){ return color(i); } }); 初出 * (scale) d3.scale.category20
  13. 4FMFDUJPO ྫ͑͹ ඥ෇͚ͨσʔλ طଘͷ%0. FYJU TFMFDUJPO FOUFS ଐੑɾελΠϧɾςΩ ετͷมߋͳͲΛߦ͏ ৽نʹ%0.Λ௥Ճ

    ͠ɺಉ࣌ʹଐੑɾελ ΠϧɾςΩετΛηο τ͢Δ طଘͷ%0.Λ࡟আ͠ ͨΓɺಁ໌౓Λ্͛ͨ ΓΛߦ͏
  14. ๮άϥϑ σʔλ࡞੒ // データ生成 var data = dataGenerator(10, function(i){ return

    { id: i, name: "name "+ i, // height よりも大きい! y: 0|Math.random() * 1000 }; });
  15. ๮άϥϑ σʔλ੔ཧ ΞΫηαΛࢦఆ͢Δ͜ͱͰɺ഑ྻ͔Βॊೈ ʹ࠷େɾ࠷খɾൣғΛऔΓग़ͤΔ ଞʹ΋ฏۉͱ͔தԝ஋ͳͲ΋Մೳ // データの調査 var min =

    d3.min(data, function(d){ return d.y;}), max = d3.max(data, function(d){ return d.y;}), extent = d3.extent(data, function(d){ return d.y;}); アクセサ 初出 * (number) d3.min / d3.max * ([number, number]) d3.extent
  16. ๮άϥϑ εέʔϧ࡞੒௒ॏཁʂTDBMFΛ੍͢͜ͱඞਢ var x = d3.scale.ordinal() .domain(data.map(function(d){ return d.id; }))

    .rangeBands([0, width], 0.2), y = d3.scale.linear() .domain([0, max]) .range([height, 0]); // [0, height]じゃない! EPNBJO ೖྗ SBOHF ग़ྗ ͷม׵ RVBOUJUBUJWFPSEJOBMͷछྨ RVBOUJUBUJWF͸ʮൣғൣғʯ PSEJOBM͸ʮ*%ൣғʯ ൣғ৘ใͷఏڙ 初出 * (scale) d3.scale.linear / d3.scale.ordinal
  17. ๮άϥϑ TDBMFͷSBOHF͕< IFJHIU>Ͱ͸ͳ͘ <IFJHIU >ͩͬͨཧ༝ ϒϥ΢β্Ͱ͸ࠨ্͕    ӈʹߦ͚͹

    Y  ɺԼʹߦ͚͹  Z  େ͖͍஋΄Ͳʮߴ͍ʯʮখ͍͞஋ʯ ߴ͞ͷ΄͏Λௐ੔ʮIFJHIUߴ͞ʯ
  18. ๮άϥϑ ཁૉͷඳըͷ४උ var bar = // 現状の取得 main.selectAll("g.bar") // データのヒモ付

    .data(data) // データ > 現状(DOM)の部分を取得 .enter() // "g"要素を追加し、classをセット .append("g") .attr({ "class": "bar", transform: function(d){ // コツ: 位置合わせをやっておく return “translate("+x(d.id)+","+height+")"; } });
  19. ๮άϥϑ ཁૉͷඳըͷ४උ var bar = // 現状の取得 main.selectAll("g.bar") // データのヒモ付

    .data(data) // データ > 現状(DOM)の部分を取得 .enter() // "g"要素を追加し、classをセット .append("g") .attr({ "class": "bar", transform: function(d){ // コツ: 位置合わせをやっておく return “translate("+x(d.id)+","+height+")"; } }); 描画上の一番下に合わせる height
  20. ๮άϥϑ ཁૉͷඳը bar.append("rect").attr({ width: x.rangeBand(), height: function(d){ return height -

    y(d.y); }, y: function(d){ return y(d.y) - height; }, fill: "red" }); // ラベルも付けておきます bar.append("text").text(function(d){ return d.y;});
  21. ๮άϥϑ ࣠ͷ࡞੒ var xaxis = main.append("g").call(d3.svg.axis().scale(x)).attr({ "class": "axis", transform: "translate(0,"+height+")"

    }); var yaxis = main.append(“g").call(d3.svg.axis().scale(y).orient("left")) .attr({ "class": "axis" }); 初出 * (svg) d3.svg.axis * (selection) selection.call
  22. 47(Ͱ࢖͑Δλά TWH H EFGT TZNCPM VTF QBUI MJOF SFDU DJSDMF

    FMMJQTF QPMZMJOF QPMZHPO ! ͋ͱ͸ϑΟϧλʔपΓ͕ͨ͘͞Μ͋Γ·͕͢ ΄ͱΜͲ࢖͏ػձ͸͋Γ·ͤΜ
  23. 1"5) ͢΂ͯͷඳըཁૉ HSBQIJDTFMFNFOU ͸͜ΕͷBMJBT ͩͱߟ͑Δ͜ͱ͕Ͱ͖·͢ EଐੑͰσʔλύεจࣈྻΛ౉͢͜ͱͰඳըͤ͞·͢ FH.--[   ͔Β։࢝

    . ͠ɺ   ʹҠಈ - ɺ   ʹҠಈͯ͠ɺด࿏Λ࡞Δ [  pMMଐੑด࿏ͷதΛࢦఆͨ͠৭ͰృΓͭͿ͢ TUSPLFଐੑύεΛࢦఆͨ͠৭Ͱඳ͘ TUSPLFXJEUIଐੑύεͷઢͷଠ͞Λࢦఆ͢Δ
  24. $*3$-& 3&$5 -*/& &--*14& DJSDMFཁૉ Sଐੑ൒ܘΛࢦఆ DYDZଐੑத৺ͷYZ࠲ඪΛࢦఆ SFDUཁૉ XJEUIIFJHIUଐੑۣܗͷ෯ߴ͞Λࢦఆ YZଐੑۣܗͷࠨ্ͷҐஔΛࢦఆ

    SYSZଐੑؙ֯ͷପԁ൒ܘΛࢦఆ MJOFཁૉ YYZZଐੑ୹఺ͷ࠲ඪΛࢦఆ FMMJQTFཁૉ DYDZଐੑପԁͷத৺Ґஔͷ࠲ඪΛࢦఆ SYSZଐੑପԁͷ൒ܘΛࢦఆ
  25. 5SBOTGPSNଐੑ USBOTGPSNଐੑʹ͸จࣈྻͰԼهΛࢦఆ͢Δ ͜ͱ͕Ͱ͖·͢ NBUSJYมܗߦྻ ཁૉ Λࢦఆ USBOTMBUFฒߦҠಈFHUSBOTGPSN 9 : 

    SPUBUFճసFHSPUBUF   TLFX9TLFX:܏ࣼ ฏߦ࢛ลܗΈ͍ͨʹ௵ ͢ FHTLFX9   TDBMF֦େॖখFHTDBMF  TDBMF  
  26. σʔλ࡞੒ // データ生成 var data = dataGenerator(10, function(i){ var now

    = Date.now(); return { id: i, name: "name "+ i, x: new Date(now + 60000 * i), // 一分おき y: 0|Math.random() * 1000 }; }); ંઢάϥϑ
  27. εέʔϧ࡞੒ // スケールの生成 var x = d3.time.scale() .domain(d3.extent(data, function(d){ return

    d.x; })) .range([0, width]), y = d3.scale.linear().domain([0, max]).range([height, 0]); ࣌ؒʹಛԽͨ͠εέʔϧ ࣗಈͰ࣌ؒͷ۠ؒΛௐ੔ͯ͘͠ΕΔͨΊɺBYJTʹར༻͠ ͨ࣌ʹศར ೥ɺ࢛൒ظɺ݄ɺ೔ɺ࣌ɺ෼ɺͳͲॊೈʂ 初出 * (scale) d3.time.scale ંઢάϥϑ
  28. ཁૉඳըϢʔςΟϦςΟ var line = d3.svg.line() .x(function(d){ return x(d.x); }) .y(function(d){

    return y(d.y); }); // PATHDATA=line([{x: X, y:Y},{}]) 配列を受けて、PathDataの文字列を返す ྨࣅͷTWHͱͯ͠BSFB BSD EJBHPOBMͳ Ͳ͕͋Δ 初出 * (function) d3.svg.line ંઢάϥϑ
  29. ඳը var serie = // 現状の取得 main.append("path") // データのヒモ付 .datum(data)

    .attr({ d: line, fill: "none", stroke: color(0) }); 初出 * (selection) selection.datum path要素に対して、配列を紐付ける ંઢάϥϑ
  30. σʔλͷ४උ ΦϒδΣΫτͷ഑ྻͷ഑ྻ // データ生成 var series = dataGenerator(3, function(i){ return

    { name: "series " + i, data: dataGenerator(10, function(j){ var now = Date.now(); return { id: j, name: "name "+ j, x: new Date(now + 60000 * j), // 一分おき y: 0|Math.random() * 1000 }; }) }; }); ෳ਺ͷંઢάϥϑ
  31. σʔλͷൣғΛऔಘ ճNJONBYΛ࢖͏ var maxY = d3.max(series, function(serie){ return d3.max(serie.data, function(d){

    return d.y;}); }); var minX = d3.min(series, function(serie){ return d3.min(serie.data, function(d){ return d.x;}); }), maxX = d3.max(series, function(serie){ return d3.max(serie.data, function(d){ return d.x;}); }); ෳ਺ͷંઢάϥϑ
  32. ඥ෇͚ͯඳը var serie = // 現状の取得 main.selectAll("g.serie") // データのヒモ付 .data(series)

    .enter() .append("g").attr({"class": "serie"}); ! serie.append("path").attr({ d: function(d){ return line(d.data); }, fill: "none", stroke: function(d){ return color(d.name); } }); ෳ਺ͷંઢάϥϑ
  33. 0OFNPSFUIJOH ֤ϙΠϯτʹυοτͱ਺஋Λ var serie = // 現状の取得 main.selectAll("g.serie") // データのヒモ付

    .data(series) .enter() .append("g").attr({ "class": "serie", fill: function(d){ return color(d.name); } }); 子要素すべてのfillを指定
  34. ඥ෇͚ͯඳը var point = serie.selectAll("g.point") .data(function(d){ return d.data;}).enter() .append("g").attr({ "class":

    "point", transform: function(d){ return "translate("+x(d.x)+","+y(d.y)+")"; } }); point.append("circle").attr({r: 5}); point.append("text").text(function(d){ return d.y; }).attr({dy: -8}); 0OFNPSFUIJOH
  35. "OJNBUJPO ߋ৽ॲཧؔ਺ લ൒ var updateLine = function(){ // スケールのドメイン更新 x.domain(d3.extent(data,

    function(d){ return d.x; })); var max = d3.max(data, function(d){ return d.y;}); y.domain([0, max]); ! // 折線の変形アニメーション serie.transition() .attr({ d: line }); ! これでアニメーションを利用できる!
  36. "OJNBUJPO ߋ৽ॲཧؔ਺ த൫ // 新たにデータが増えたのでselection撮り直し var point = main.selectAll("g.point").data(data); //

    データ追加分の処理 var newpoint = point.enter().append(“g") .attr({"class": "point", fill: color(0), transform: function(d){ return "translate("+x(d.x)+","+y(d.y)+")"; } }); newpoint.append("circle").attr({ r: 5 }); newpoint.append("text").text(function(d){return d.y;}).attr({dy:-8}); // 既存データのアニメーション point.transition().attr({ transform: function(d){ return "translate("+x(d.x)+","+y(d.y)+")"; } });
  37. σʔλՄࢹԽͷϚϯτϥ Overview First, Zoom and Filter, Then Details-on-Demand Overview First,

    Zoom and Filter, Then Details-on-Demand Overview First, Zoom and Filter, Then Details-on-Demand Ben Shneiderman $