Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
D3.js 資料視覺化入門
Search
Kuro Hsu
December 23, 2015
Technology
2
240
D3.js 資料視覺化入門
2015/12/23 @ 朝陽科技大學
Kuro Hsu
December 23, 2015
Tweet
Share
More Decks by Kuro Hsu
See All by Kuro Hsu
Laravel x Vite
kurotanshi
0
610
[.NET Conf 2020 Taiwan] 以輕前端視角進入 Vue 3.0 的世界
kurotanshi
0
700
[MOPCON 2020] vite: Make web dev fast again
kurotanshi
0
2.3k
[ModernWeb'20] Vue.js :The Bad Parts
kurotanshi
1
100
[MOPCON 2019] Vue.js 3.0 與 Composition API 的變革
kurotanshi
1
1.2k
[JSDC2019] 我有一堆選擇 Vue 開發框架的理由
kurotanshi
1
730
[COSCUP 2019] 前端工程師的養成之路與開源工具
kurotanshi
3
390
初探 Vue 3.0 Function API
kurotanshi
4
3k
VueJS Style Guide 導讀
kurotanshi
6
1.8k
Other Decks in Technology
See All in Technology
今年一年で頑張ること / What I will do my best this year
pauli
1
220
Formal Development of Operating Systems in Rust
riru
1
420
AWS re:Invent 2024 re:Cap Taipei (for Developer): New Launches that facilitate Developer Workflow and Continuous Innovation
dwchiang
0
160
[IBM TechXchange Dojo]Watson Discoveryとwatsonx.aiでRAGを実現!座学①
siyuanzh09
0
110
RubyでKubernetesプログラミング
sat
PRO
4
160
Azureの開発で辛いところ
re3turn
0
240
Alignment and Autonomy in Cybozu - 300人の開発組織でアラインメントと自律性を両立させるアジャイルな組織運営 / RSGT2025
ama_ch
1
2.4k
カップ麺の待ち時間(3分)でわかるPartyRockアップデート
ryutakondo
0
140
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
6
54k
I could be Wrong!! - Learning from Agile Experts
kawaguti
PRO
8
3.4k
商品レコメンドでのexplicit negative feedbackの活用
alpicola
1
340
embedパッケージを深掘りする / Deep Dive into embed Package in Go
task4233
1
210
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
27
1.5k
YesSQL, Process and Tooling at Scale
rocio
170
14k
Why Our Code Smells
bkeepers
PRO
335
57k
A Philosophy of Restraint
colly
203
16k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Adopting Sorbet at Scale
ufuk
74
9.2k
How to Ace a Technical Interview
jacobian
276
23k
Building an army of robots
kneath
302
45k
VelocityConf: Rendering Performance Case Studies
addyosmani
327
24k
Fireside Chat
paigeccino
34
3.1k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Transcript
Kuro Hsu @ ๖檚ᑀದय़䋊 D3.js 虻碘憙憽玕獈槹 2015/12/23
ᛔ౯Օ奧 Kuro Hsu • 獮ᒒૡ纷䒍 @ 睃瞆叨褸㿁 • COSCUP 拻ᘏ
• JSDC 拻ᘏ • kurotanshi [at] gmail.com • http://kuro.tw
̿ض獨ᓕ D3 ԧ牧֦肯螂虻懱憙憽玕㻟牫̀ 磪䷱磪Օ奧 D3.js 墋䁭ጱᒫӞ殷疰ݞՈ獨ᓕ D3 ጱ獌ܠ
ݶ䰬ฎ Web 懿袅獤ຉ牧ߺ㮆ฃ睞牫
ݶ䰬ฎ Web 懿袅獤ຉ牧ߺ㮆ฃ睞牫
傶Ջ讕襑ᥝ疥虻懱憙憽玕 • य़ᰁ虻碘ݢࣁ縣樌ᤩቘ薹牧虻懱㯽螏ๅ磪硳ሲ • 磪ۗෝ薪疗ڊٌ犢珊匍ොୗ犋ฃ疗憽کጱ虻碘粬 • ݢ犥盄ฃ፡ڊ虻碘蛪ጱቭ綦膏梊藮 • ֵአٌ犢承ጱ捝ᘏ犖胼ฃ፡睞
None
None
None
蕣֢虻懱瑽蔭ጱᥝᔰ • ก嘦ጱԆ氂 • 虻懱羊墋玕牧Ԇ氂ๅ统ڊ • 殼䛑憙憽㵕娄牧珅捝ᘏፓط • 篷襑ਁ藯ก犖胼ቘ薹
None
http://d3js.org/ Demo: https://goo.gl/idrDMt
None
* svg 媑瑽襑ᥝ IE9+
• D3 = Data-Driven Documents. • ֵአ翕殷秂伛ದ蔩 (HTML / CSS
/ JavaScript / SVG) • 䔶य़ጱ Data-Driven 疥虻碘䌘䛑ک DOM Ӥ牧۱ೡزᔰ ጱी㳫现痀虋玕 • ׀ SVG ፘ橕媑瑽ૡٍ䓚牧蒈圸 SVG ኴጱ jQuery • 䕃᩻य़֕䋿֢斃ٌ犢憙憽玕ૡٍ耆卓 D3.js ฎՋ讕
螡䢔瑊膏 DOM 砺֢
螡䢔瑊 JavaScript jQuery D3.js document.querySelectorAll(".block") $(".block") d3.selectAll(".block")
螡䢔瑊 d3.select("body").selectAll(".block") d3.selectAll("body .block")
ොဩ袽 (method chaining) var box = d3.selectAll('.box'); box.style('color', '#f00');
box.text('Hello World!'); var box = d3.selectAll('.box') .style('color', '#f00') .text('Hello World!');
痀 (attr) // attr() d3.selectAll("circle") .attr("cx", 50) .attr("cy", 50)
.attr("r", 25) .style("fill", "red");
痀 (attr) // 犥̿ᇔկ̀ጱොୗ瞲ਧ痀 d3.selectAll("circle") .attr({ "cx": 50, "cy":
50, "r": 25 }) .style("fill", "red"); // 玲 circle cx 痀ጱ独 d3.select("circle").attr("cx");
痀 (property) d3.selectAll('.name') .property('value', 'Kuro'); አဩ膏 attr() ፘݶ牧֕
property() ֵአࣁ篷ਁᶎ瞲ਧጱ痀牐 ই: disabled, checked 犥现 value 缛牐 d3.selectAll('.name') .property('disabled');
class d3.selectAll('.block') .classed('item', true); d3.selectAll('.block') .classed('item', false);
d3.selectAll('.block') .classed('item big', true);
styles d3.selectAll('.block') .style('color', '#f00'); d3.selectAll('.block') .style({ 'color':
'#f00', 'font-size': '15px' });
text & html var foo = d3.selectAll('.foo'); foo.text('Hello World!'); foo.html('<div
class="bar">Hello</div>');
ℂ虻碘ک瑽猟زᔰ
Data - ಅ磪ጱ虻碘᮷ฎ檋ڜ var data = [1, 3, 5, 2,
4, 6, 8, 10];
Data - ಅ磪ጱ虻碘᮷ฎ檋ڜ jsbin.com/kifihirugu var data = [ {x: 10.0,
y: 9.14}, {x: 8.0, y: 8.14}, {x: 13.0, y: 8.74}, {x: 9.0, y: 8.77}, …… ];
key function var data = [ { 'name': 'kuro', 'age':
30 }, { 'name': 'John', 'age': 20 }, { 'name': 'Mary', 'age': 18 } ]; var p = d3.select('body') .selectAll('p') .data(data) .enter() .append('p') .text(function(d, i) { return d.name + ': ' + d.age + '䵇'; });
None
Enter, Update, Exit Pattern var data = [1, 2,
3, 4, 5]; d3.select('body') .selectAll('div') .data( data ) .enter() .append('div') .text(function(d, i){ return d; }); 1 2 3 4 5
Enter, Update, Exit Pattern data = [1, 3, 5,
7, 9]; d3.select('body') .selectAll('div') .data( data ) .text(function(d, i){ return d }); 1 3 5 7 9
Enter, Update, Exit Pattern data = [10, 20, 30]; d3.select('body')
.selectAll('div') .data( data ) .exit() .remove(); 1 3 5 7 9
Enter, Update, Exit Pattern data = [10, 20, 30]; d3.select('body')
.selectAll('div') .data( data ) .exit() .remove(); 1 3 5 7 9 ?
Enter, Update, Exit Pattern data = [10, 20, 30]; d3.select('body')
.selectAll('div') .data( data ) .text( function(d, i){ return d; }) .exit() .remove(); 10 20 30 7 9
None
SELECTION Datas Enter & Update Exit & Remove SELECTION
Enter: Data > Elements. Update: Data = Elements. Remove: Data
< Elements.
Ajax with D3 d3.json([URL], function(error, data){ if (error) return console.warn(error);
// do something }); d3.csv([URL]).get(function(error, data){ // do something });
穉ֺ疳膏ଷ秂數
d3.scale.linear().domain().range() 補間⽅法 輸入範圍 輸出範圍
Domain Range
穉ֺ疳 0 1000 0 100 500 50 Domain Range
var d3Scale = d3.scale.linear() // linear .domain([0, 1000]) //
㯽獈塅瑻 .range([0, 100]); // 蜍ڊ塅瑻 console.log( d3Scale(500) ); // 50 console.log( d3Scale(123) ); // 12.3 穉ֺ疳
var colorScale = d3.scale.linear() .domain([0, 20]) .range(["#f00", "#0f0"]); for (var
i = 0; i < 21; i++) { body.append('div') .style('background-color', colorScale(i)); }
var widthScale = d3.scale.linear() .domain([0, 12]) .range(["0px", "720px"]); for (var
i = 0; i < 13; i++) { body.append('div').text( widthScale(i) ); }
var red = d3.rgb(255,0,0); var green = d3.rgb(0,255,0); var compute
= d3.interpolate(red, green); console.log( compute(0) ); // #ff0000 console.log( compute(0.3) ); // #b34d00 console.log( compute(0.5) ); // #808000 console.log( compute(0.7) ); // #4db300 console.log( compute(1) ); // #00ff00
var a = "50px"; var b = "1000px"; var compute
= d3.interpolate(a, b); console.log( compute(0) ); // 50px console.log( compute(0.3) ); // 335px console.log( compute(0.5) ); // 525px console.log( compute(0.7) ); // 715px console.log( compute(1) ); // 1000px
d3.scale.category10() d3.scale.category20() d3.scale.category20b() d3.scale.category20c()
ଷ秂數
數娄 var data = [0, 150, 200, 300, 500, 1000];
// x 數 scale 穉ֺ疳 var xScale = d3.scale.linear() .domain(d3.extent(data)) // [0, 1000] .range([0, 500]); // x-range አ㬵蔭纈疝ଶ // y 數 scale 穉ֺ疳 var yScale = d3.scale.linear() .domain(d3.extent(data)) // [0, 1000] .range([0, 300]); // y-range አ㬵蔭纈ṛଶ
數娄 // x 數 var xAxis = d3.svg.axis() .scale(xScale) .orient("bottom");
// ڰଶ֖ᗝ // y 數 var yAxis = d3.svg.axis() .scale(yScale) .orient("left"); // ڰଶ֖ᗝ
數娄 蝚螂 orient() 矒ګ數娄ොݻ现ڰଶ֖ᗝ
Ticks - ڰଶ jsbin.com/cuvubiwipo // x 數 var xAxis =
d3.svg.axis() .scale(xScale) .orient("bottom") .ticks(15) // 瞲ਧڰଶ碍ᰁ, 㻌֖ .tickFormat(function(d){ return d + "px"; }); // y 數 var yAxis = d3.svg.axis() .scale(yScale) .orient("left");
裾礿瑽
㾼讨瑽
穥ု瑽 http://jsbin.com/yepapa
螂䁰㵕向 SELECTION.transition() .duration(1000) // 㵕向䁆ᤈ碻樌 .delay(1000) // 皤螛 .ease( ...
) // Easing 獢碍 .attr({ 'transform': function(d){ ....... } }); *D3.js Easing Checker - http://bl.ocks.org/hunzy/9929724
螂䁰㵕向 SELECTION.transition() .duration(1000) .each('start', function(){ … }) // 㵕向樄ত獮䁆ᤈ .attr({
… }) .each('end', function(){ … }); // 㵕向奾盅䁆ᤈ
ے獈Ԫկ SELECTION.on('click', function(){ alert('Hello D3!'); }); SELECTION.on('click', null);
ے獈Ԫկ SELECTION.on('click.event1', function(){ alert('Hello D3 event 1'); }); SELECTION.on('click.event2', function(){
alert('Hello D3 event 2'); });
穥ု瑽ےӤ㵕向硳ຎ
SVG च器
SVG 讨檋ୗ瑽粙婘硯碻䨝叨ኞ०፥硳䛑 source: http://www.cs.cmu.edu/~chuck/lennapg/lenna.shtml
SVG ݻᰁୗ瑽粙ኧӞ蝫Ԁଷ秂懯ᓒ奲౮牧硯ٚय़犖犋ொ source: http://komica.chiisana.net/vector/src/1205520731301.svg
rect <rect x="20" y="20" width="150" height="100" rx="0"></rect>
circle <circle cx="55" cy="55" r="50"></circle>
line <line x1="10" y1="30" x2="230" y2="60"></line> x1, y1 x2, y2
text <text x="0" y="0" dx="0" dy="0" font-size="50" text-anchor="start"> Hello
</text> text-anchor="[start/middle/end]"
text - tspan <text x="0" y="20" style="font-size: 17px;"> <tspan>Hello,
</tspan> <tspan fill="red">World </tspan> </text>
text - tspan <text x="0" y="20" style="font-size: 17px;"> <tspan
x="10" dy="10">Hello, </tspan> <tspan x="10" dy="20">World </tspan> </text>
g (group) <g transform="rotate(45 50 50)"> <line> … </line> <rect>
… </rect> <text> … </text> </g>
path • 犨娄ྦྷጱ奲ݳ牧ಅ磪瑽୵᮷向ڊ㬵 • d 痀物Ӟᗭ̿瞲犤̀+̿ଷ秂̀ጱ奲ݳ
path • ᑏ㵕: M (MoveTo) • ፗ娄: L (LineTo) /
H (Horizontal) / V (Vertical) • ใ娄: C (CurveTo) / S (Shorthand/Smooth CurveTo) Q (Quadratic Bezier CurveTo) T (smooth quadratic Bezier CurveTo) • 皭娄: A (elliptical Arc) • 樂ݳ: Z (close-path)
path <line x1="10" y1="50" x2="390" y2="130"> <path d="M10,50L390,130">
娄ྦྷ叨ኞ瑊 - d3.svg.line var linePath = d3.svg.line(); var data =
[[10,50], [390, 130]]; svg.append('path') .attr('d', linePath(data)); <path d="M10,50L390,130">
娄ྦྷ叨ኞ瑊 - d3.svg.line var svg = d3.select('.svg'); var linePath
= d3.svg.line() .x(function(d, i){ return d; }) .y(function(d, i){ return (i%2 === 0) ? 40 : 120;}) var data = [40, 80, 120, 160, 200, 240, 280, 320, 360]; svg.append('path') .attr({ 'd': linePath(data) });
ರ娄瑽
d3.svg.line() .x(…).y(…) .interpolate("linear"); .interpolate("linear-closed"); .interpolate("basis"); .interpolate("cardinal"); .interpolate("step"); https://github.com/mbostock/d3/wiki/SVG-Shapes#user-content-line_interpolate
ರ娄瑽 - 虋୵
ୡ娄ྦྷ叨ኞ瑊 - d3.svg.arc
ୡ娄ྦྷ叨ኞ瑊 - d3.svg.arc var myArc1 = { "startAngle": 0, "endAngle":
Math.PI }; var myArc2 = { "startAngle": Math.PI, "endAngle": Math.PI * 1.5 }; var myArc3 = { "startAngle": Math.PI * 1.5, "endAngle": Math.PI * 2 };
ୡ娄ྦྷ叨ኞ瑊 - d3.svg.arc var arc = d3.svg.arc() .innerRadius(50) .outerRadius(150); svg.append('path')
.attr({ 'd': arc(myArc1) });
ୡ娄ྦྷ叨ኞ瑊 - d3.svg.arc
ୡ娄ྦྷ叨ኞ瑊 - d3.svg.arc http://community.yungching.com.tw/Building/9443
ୡ娄ྦྷ叨ኞ瑊 - d3.svg.arc
Responsive with D3
www.nytimes.com/interactive/2015/06/17/world/middleeast/map-isis-attacks-around-the-world.html
www.nytimes.com/interactive/2015/06/17/world/middleeast/map-isis-attacks-around-the-world.html
Responsive with D3
Responsive with D3 // 疥疳ੑ硬౮ܨ碻玲ጱ疝ṛ width = parseInt(d3.select(".content").style("width")) -
margin*2; height = parseInt(d3.select(".content").style("height")) - margin*2; // 䌃稴ጱ疝ṛ var margin = 40, width = 960 - margin*2, height = 500 - margin*2;
var svg = d3.select('.svg'); // 疥媑蕣㵕֢۱蕕ᛗ function 獉 function
rendering() { // 疥媑蕣ጱ纷ୗ嘨蝢蝢砆ک愊ᶎ // ኼ } // 疥 window 翉ਧ resize Ԫկ牧㪔᯿碝媑蕣瑽ࣳ d3.select(window).on('resize', rendering); // Ḓ稞媑蕣 rendering();
None
// resize 碻, 㵕眲ๅ碝 x, y 數ڰଶ, ๅ螕ݳ褂捝 var yAxis
= d3.svg.axis() .scale(yScale2) .orient("left") .ticks( Math.max(height/50, 2) ); Responsive with D3
None
Responsive with D3 • य़ग़碍ᤈ㵕蕕ᗝ䌘 SVG ඪൔ臑অ • ݻᰁ瑽୵牧婘硯犋०፥ •
㵕向 / زᔰ螂ग़碻ฃ磪硳胼㺔氂 • 犋ฎ犨֜瑽୵᮷螕ݳࣁಋ秚Ӥ氥纈物 狶 RWD ฎݚ狶Ӟ㮆ಋ秚粚牫
d3 Layouts
D3.js Layouts • d3.js ׀ԧ 11 圵粚ࣳ (layouts) • ݝ襑׀扗粚ࣳ瞲ਧጱ虻碘໒ୗ疰ݢ犥ፗ矑ॺአ
• layouts 蛪犋׀媑瑽ۑ胼牧ᘒฎ疥ܻতጱ虻碘 旉矦౮螕ݳᤩ d3 媑瑽ጱ虻碘໒ୗ • 睱懯ᓒ top, left, d 缛缛痀ጱ碻狡粬獨অአ
Pie Layout
Pie Layout - Ӟᑁ虋綎綎瑹
Chord Layout 2015 ᒫӞ䌵Ӯኴ12䔶༉純搴 A 奲毆搴䌘䜗奾ຎ
Chord Layout ݣ傀 ݘ૬ 艰葦 ے೭ य़ ူग़ 讝ݱ 嬝य़ڥ
ݣ傀 - 4 4 8 4 7 ݘ૬ 1 - 6 1 8 2 艰葦 7 5 - 1 11 16 ے೭य़ 9 5 3 - 2 4 ူग़ 讝ݱ 7 7 7 0 - 7 嬝य़ڥ 1 1 1 0 1 -
Chord Layout
Chord Layout
Chord Layout
Chord Layout
Hierarchy Layout 塅ֺ虻碘: 2014 ݣ玖૱裾螡膐ݱᤈ硰玟ಭ纏翄懯
Partition Layout
Partition Layout // 疥ኞ౮অጱ nodes 蝚螂 data() 癲獈 var gRects
= svg.selectAll("g").data(nodes).enter().append("g"); // ے獈 rect gRects.append("rect").attr({ ... }).style({ ... }); // ے獈ਁ gRects.append("text").attr({ ... }).style({ ... }); // 縷୵褩䍅瑽: d3.layout.partition() // size 瞲ਧ瑽礯य़ੜ, ڥአ .nodes 癲獈虻碘 var nodes = d3.layout.partition() .size([600, 400]) // [width, height] .nodes(data);
Partition Layout
Partition Layout // 㾼୵褩䍅瑽: d3.layout.partition() // size 瞲ਧ瑽礯य़ੜ, ڥአ .nodes
癲獈虻碘 var nodes = d3.layout.partition() .size([2 * Math.PI, radius * radius]) .nodes(data); // d3.svg.arc 蕣֢皭୵ var arc = d3.svg.arc() .startAngle(function (d) { return d.x; }) .endAngle(function (d) { return d.x + d.dx; }) .innerRadius(function (d) { return Math.sqrt(d.y); }) .outerRadius(function (d) { return Math.sqrt(d.y + d.dy); });
http://bl.ocks.org/mbostock/1256572
捝ᘏ蚤֦మጱ犋Ӟ䰬 ইຎ獉瑹դ蔭 100牧 क़瑹䨝ฎग़牫
捝ᘏ蚤֦మጱ犋Ӟ䰬 500 1500
捝ᘏ蚤֦మጱ犋Ӟ䰬 500 1500 1500 500
憙憽玕犋ฎ磪瑽疰অ 瑽粙㬵რ物 https://www.facebook.com/forpeople/photos/a. 989035831154301.1073741835.153819538009272/989036197820931/
憙憽玕犋ฎ笖犝疰অ (睃瞆լ翕ᤈ眐毱螇) (礓瞆լ翕ᒊ)
窾窫憙肯
ై螡Ԇ氂
ై螡Ԇ氂 0 200000000000000000000 400000000000000000000 600000000000000000000 800000000000000000000 1000000000000000000000 ྎॠ聲䒍 碝ڥ
None
http://p.udn.com.tw/upf/newmedia/2015_data/20150930_udntyphoon/udntyphoon/index.html
None
http://blog.infographics.tw/
None
– Randy Krum, Author of Cool Infographics. ̿፡ک牧疰睞ԧ牐̀
Q & A
• Kuro Hsu • Demo code: https://github.com/kurotanshi/d3js-samples • kurotanshi [at]
gmail.com • http://kuro.tw Thanks!