codemotion 2016 - d3.js un taller divertido y difícil

75
Un taller de d3.js difícil y divertido* ¿qué necesitas para hacer visualizaciones de datos impresionantes? *http://www.macwright.org/presentations/d Javier Abadía @javierabadia

Upload: javier-abadia

Post on 16-Apr-2017

325 views

Category:

Internet


1 download

TRANSCRIPT

Page 1: Codemotion 2016 - d3.js un taller divertido y difícil

Un taller de d3.js difícil y divertido*

¿qué necesitas para hacer visualizaciones de datos impresionantes?

*http://www.macwright.org/presentations/dcjq/

Javier Abadía@javierabadia

Page 2: Codemotion 2016 - d3.js un taller divertido y difícil

¿por qué es difícil?

Page 3: Codemotion 2016 - d3.js un taller divertido y difícil

¿y por qué es divertido?

Page 5: Codemotion 2016 - d3.js un taller divertido y difícil

un gráfico de barras

Page 6: Codemotion 2016 - d3.js un taller divertido y difícil

nop!

Page 7: Codemotion 2016 - d3.js un taller divertido y difícil

de cabeza!

http://bl.ocks.org/mbostock/4062006

Page 8: Codemotion 2016 - d3.js un taller divertido y difícil

logística• ¿os funciona todo?• https://github.com/jabadia/d3-workshop

Page 9: Codemotion 2016 - d3.js un taller divertido y difícil

¿qué queremos conseguir?1. preparar los datos2. elegir el tipo de visualización apropiado3. buscar un ejemplo (p.ej. en bl.ocks.org) parecido4. cambiar los datos5. cambiar la apariencia6. adaptar la interacción7. integrarlo en mi app

contar una historiacon los datos

Page 10: Codemotion 2016 - d3.js un taller divertido y difícil

al lío…

Page 11: Codemotion 2016 - d3.js un taller divertido y difícil

Un poco de teoríad3.js, Javascript Nivel Demonio+

Page 12: Codemotion 2016 - d3.js un taller divertido y difícil

d3.js• no es una herramienta de visualización– Tableau, Excel, R-studio

• no es una librería de gráficas– highcharts.js, google charts, dimple, nvd3

• no es una librería de mapas– leaflet.js

• no es una librería de dibujo– SVG, Canvas

Page 13: Codemotion 2016 - d3.js un taller divertido y difícil

entonces, que es?

Page 14: Codemotion 2016 - d3.js un taller divertido y difícil

DataDrivenDocumentsDDD

3

Page 15: Codemotion 2016 - d3.js un taller divertido y difícil

¿qué tiene de especial?

DATOSJSONCSVTSV …

Page 16: Codemotion 2016 - d3.js un taller divertido y difícil

d3 necesita JS nivel Demonio+

Page 17: Codemotion 2016 - d3.js un taller divertido y difícil
Page 18: Codemotion 2016 - d3.js un taller divertido y difícil

funciones

http://www.smashingmagazine.com/2014/07/dont-be-scared-of-functional-programming/

Page 19: Codemotion 2016 - d3.js un taller divertido y difícil

function aceptaDos(a, b){ a = a || ‘default A’; 🌶 b = b || ‘default B’; return a + b + arguments[2];}

aceptaDos(); // legalaceptaDos(‘pA’); // legalaceptaDos(‘pA’,’pB’); // legalaceptaDos(‘pA’,’pB’,’pC’); // legal

Page 20: Codemotion 2016 - d3.js un taller divertido y difícil

function modifica1(s){ return 'un ' + s + ' precioso';}

function modifica2(s){ return 'el mejor ' + s + ' de todos';}

function generaDia(m){ return m('dia');}

generaDia(modifica1); // ‘un dia precioso’generaDia(modifica2); // ‘el mejor dia de todos’

Page 21: Codemotion 2016 - d3.js un taller divertido y difícil

function modifyString(){ var prefix='|'; var postfix='|';

var output = function(s) { return prefix + s + postfix; }

output.prefix = function(p) { prefix = p; return output; } output.postfix = function(p) { postfix = p; return output; }

return output;}

m = modifyString().prefix(‘un’).postfix(‘precioso’);m(‘dia’) // ‘un dia precioso’

❶ ❷ ❹

Page 22: Codemotion 2016 - d3.js un taller divertido y difícil

e.attr('x', function(d) { return x(d); })

e.attr('x', x)

e.attr('x', function(d) { return this.x(d); })

=>=>

Page 23: Codemotion 2016 - d3.js un taller divertido y difícil

¿lo tenéis?

Page 24: Codemotion 2016 - d3.js un taller divertido y difícil

¿quien sabe jQuery?

Page 25: Codemotion 2016 - d3.js un taller divertido y difícil

selecciones

lis = $(‘li’)lis.length

lis.each( function() { console.log(this); } )lis.each( function() {$(this).fadeOut(); } ) 🌶lis.each( function() {$(this).fadeIn(); } ) 🌶

lis.fadeOut()lis.fadeIn()lis.css({color: ‘red’})

<ul><li>a</li><li>b</li><li>c</li><li>d</li><li>e</li></ul>

Page 26: Codemotion 2016 - d3.js un taller divertido y difícil

más selecciones• jQuery– $(‘li’).css(‘background-color’,’red’);

• D3– d3.selectAll(‘.bar’).attr(‘fill’,’red’);

• pero…– d3.selectAll(‘.bar’).data(meses);

Page 27: Codemotion 2016 - d3.js un taller divertido y difícil

los joins

Page 28: Codemotion 2016 - d3.js un taller divertido y difícil

<ul><li>Java</li><li>C</li><li>C++</li><li>C#</li><li>Python</li><li>JavaScript</li><li>Visual Basic .NET</li><li>Perl</li><li>Objective-C</li><li>Assembly language</li><li>Swift</li><li>Ruby</li><li>Visual Basic</li><li>Delphi/Object Pascal</li><li>Go</li><li>Groovy</li><li>R</li><li>MATLAB</li><li>PL/SQL</li></ul>

var progLang = [ 'Java', 'C', 'C++', 'C#', 'Python', 'JavaScript', 'PHP', 'Visual Basic .NET', 'Perl', 'Objective-C', 'Assembly language', 'Swift', 'Ruby', 'Visual Basic', 'Delphi/Object Pascal', 'Go', 'Groovy', 'R', 'MATLAB', 'PL/SQL',];

Page 29: Codemotion 2016 - d3.js un taller divertido y difícil

var progLang = [ 'Java', …, 'PL/SQL'];

var list = d3.select('ul');var items = list.selectAll('li.lang').data(progLang);

items.enter().append('li') .attr('class', 'lang') .text(String);… .text(function(d) { return String(d); });

❶❸❷

❺❻

Page 30: Codemotion 2016 - d3.js un taller divertido y difícil

selection.attr(‘x’, function(d, i) { … }).text(function(d, i) { … }).property(‘selected’, function(d, i) { … }).style(‘opacity’, function(d, i) { … })

this.__data__

function(d,i,data) { … }

d = datoi = índice del datodata = array de todos los datosthis = nodo DOM

Page 31: Codemotion 2016 - d3.js un taller divertido y difícil

al lío

Page 32: Codemotion 2016 - d3.js un taller divertido y difícil

Más teoríaVisualización de datos, codificación visual

Page 33: Codemotion 2016 - d3.js un taller divertido y difícil

valores

codificaciónvisual

https://www.safaribooksonline.com/library/view/designing-data-visualizations/9781449314774/

Page 34: Codemotion 2016 - d3.js un taller divertido y difícil

var x = d3.scaleLinear() .domain([10, 130]) .range([0, 960]);

x(20); // 80x(50); // 320

var color = d3.scaleLinear() .domain([10, 100]) .range(["brown", "steelblue"]);

color(20); // "#9a3439"color(50); // "#7b5167"

var x = d3.scaleTime() .domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]) .range([0, 960]);

x(new Date(2000, 0, 1, 5)); // 200x(new Date(2000, 0, 1, 16)); // 640x.invert(200); // Sat Jan 01 2000 05:00:00 GMT-0800 (PST)x.invert(640); // Sat Jan 01 2000 16:00:00 GMT-0800 (PST)

Page 35: Codemotion 2016 - d3.js un taller divertido y difícil

var x = d3.scalePoint() .domain(["a", "b", "c"]) .range([0, width]);

var x = d3.scaleBand() .domain(["a", "b", "c"]) .range([0, width]) .padding(0.05);

var c = d3.scaleOrdinal() .domain(["apple", "orange", "banana", "grapefruit"]) .range(["green”, ”orange”, ”yellow”, ”red"]);

Page 36: Codemotion 2016 - d3.js un taller divertido y difícil

ahora si que noos libráis de las barras

Page 37: Codemotion 2016 - d3.js un taller divertido y difícil

Datos dinámicos y movimientoAnimación, actualización de datos, story-telling

Page 38: Codemotion 2016 - d3.js un taller divertido y difícil

['Python', 'JavaScript', 'PHP', 'Visual Basic .NET', 'Perl', 'Objective-C', 'Assembly language', 'Swift', 'Ruby', 'Visual Basic', 'Delphi/Object Pascal','Go', 'Groovy', 'R', 'MATLAB', 'PL/SQL', ]

<ul><li>Java</li><li>C</li><li>C++</li><li>C#</li><li>Python</li><li>JavaScript</li><li>Visual Basic .NET</li><li>Perl</li><li>Objective-C</li><li>Assembly language</li><li>Swift</li><li>Ruby</li><li>Visual Basic</li><li>Delphi/Object Pascal</li><li>Go</li></ul>

EXIT

UPDATEUPDATE

ENTER

Page 39: Codemotion 2016 - d3.js un taller divertido y difícil
Page 40: Codemotion 2016 - d3.js un taller divertido y difícil

var bars = svg.selectAll('rect.bar').data(visibleWeather, day);

console.log(bars.enter().size(), bars.size(), bars.exit().size());

bars.enter() // ENTER .append('rect') .attr('class','bar') .attr('x', function(d,i) { return x(i) + x.bandwidth(); }) .attr('width', x.bandwidth()) .attr('y', function(d) { return y(tempMin(d)); }) .attr('height', function(d) { return y(tempMax(d)-tempMin(d)); }) .style('fill', function(d) { return color(tempMin(d));}).transition() .attr('x', function(d,i) { return x(i); })

bars // UPDATE .transition() .attr('x', function(d,i) { return x(i); }) .attr('width', x.bandwidth()) .attr('y', function(d) { return y(tempMin(d)); }) .attr('height', function(d) { return y(tempMax(d)-tempMin(d)); })

bars.exit() // EXIT .remove()

Page 41: Codemotion 2016 - d3.js un taller divertido y difícil
Page 42: Codemotion 2016 - d3.js un taller divertido y difícil

going out of the boxlayouts, arcs, paths

Page 43: Codemotion 2016 - d3.js un taller divertido y difícil

layouts• Bundle• Chord• Cluster• Force• Histogram• Pack• Partition• Pie• Stack• Tree• Treemap• …

datos

datos más fáciles de pintar

{ region: ‘Norte’, ventas: 11245}

{ startAngle: 0, endAngle: 0.124, data: { region: ‘Norte’, ventas: 11245 }}

data

pie(data)

Page 44: Codemotion 2016 - d3.js un taller divertido y difícil

arc• d3.arc() es una función que devuelve un generador de arcos– un arco es un path de SVG

• se puede/suele configurar con parámetros fijos

var arc = d3.arc();

arc({ innerRadius: 0, outerRadius: 100, startAngle: 0, endAngle: Math.PI / 2}); // "M0,-100A100,100,0,0,1,100,0L0,0Z"

var arc = d3.arc() .innerRadius(0) .outerRadius(100) .startAngle(0) .endAngle(Math.PI / 2);

arc(); // "M0,-100A100,100,0,0,1,100,0L0,0Z"

Page 45: Codemotion 2016 - d3.js un taller divertido y difícil

pie y arc trabajan juntosvar arc = d3.svg.arc() .outerRadius(radius - 10) .innerRadius(0);

var pie = d3.layout.pie() .sort(null) .value(function(d) { return d.population; });

var g = svg.selectAll(".arc").data(pie(countries)) .enter().append("path") .attr("class", "arc") .attr("d", arc) .style("fill", function(d) { return color(d.data.age); });

la mitad de los parámetros

la otra mitadWTF?

http://bl.ocks.org/mbostock/3887235

Page 46: Codemotion 2016 - d3.js un taller divertido y difícil

¡dale manolo!

Page 47: Codemotion 2016 - d3.js un taller divertido y difícil

tu propio layout

var resultados = [{sCandidatura: ’pp', iEscanos: 23 },{sCandidatura: ’psoe', iEscanos: 20 },{sCandidatura: ’podemos', iEscanos: 11 },{sCandidatura: ’ciudadanos', iEscanos: 7 },];

Page 48: Codemotion 2016 - d3.js un taller divertido y difícil

nos preparamos los datosvar resultados = [{sCandidatura: ’pp', iEscanos: 23 },{sCandidatura: ’psoe', iEscanos: 20 },{sCandidatura: ’podemos', iEscanos: 11 },{sCandidatura: ’ciudadanos', iEscanos: 7 },];

var diputados = [ ’pp0’, ‘pp1’, ’pp2’, …, ’pp22’, ‘psoe0’, ’psoe1’, …,’psoe19’, ’podemos0’, …, …, ’ciudadanos6’];

Page 49: Codemotion 2016 - d3.js un taller divertido y difícil

mi layoutvar squaresLayout = function(squaresPerRow, width, gapRatio){ var squareSize = width / (squaresPerRow + (squaresPerRow-1) * gapRatio); var gapSize = squareSize * gapRatio;

var layout = function(data) { return _.map(data, function(d, i) { var row = Math.floor(i / squaresPerRow); var col = i - (row*squaresPerRow); return { row: row, col: col, x: col * squareSize + col * gapSize, y: row * squareSize + row * gapSize, data: d, }; }); } layout.squareSize = squareSize; layout.gapSize = gapSize; layout.squaresPerRow = squaresPerRow;

return layout;};

layout = squaresLayout(escanosPorFila, width, gapRatio);

var squares = svg.select('.squares').datum(diputados) .selectAll('rect.square').data(layout, function(d) { return d.data.idDiputado; });

WTF?

Page 50: Codemotion 2016 - d3.js un taller divertido y difícil
Page 51: Codemotion 2016 - d3.js un taller divertido y difícil

story-tellingelegir el layout, animaciones

Page 52: Codemotion 2016 - d3.js un taller divertido y difícil
Page 53: Codemotion 2016 - d3.js un taller divertido y difícil
Page 54: Codemotion 2016 - d3.js un taller divertido y difícil
Page 55: Codemotion 2016 - d3.js un taller divertido y difícil
Page 56: Codemotion 2016 - d3.js un taller divertido y difícil
Page 57: Codemotion 2016 - d3.js un taller divertido y difícil
Page 58: Codemotion 2016 - d3.js un taller divertido y difícil
Page 59: Codemotion 2016 - d3.js un taller divertido y difícil
Page 60: Codemotion 2016 - d3.js un taller divertido y difícil

http://www.datamake.io/project/film-money

Page 62: Codemotion 2016 - d3.js un taller divertido y difícil

crossfilter - dc.js

http://square.github.io/crossfilter/https://dc-js.github.io/dc.js/

Page 63: Codemotion 2016 - d3.js un taller divertido y difícil

d3.js v3 ▶v4no toques… ¿por que tocas?

Page 64: Codemotion 2016 - d3.js un taller divertido y difícil

librería modularv3<script src="https://d3js.org/d3.v3.js"></script>

v4<script src="https://d3js.org/d3.v4.js"></script>

<script src="https://d3js.org/d3-array.v1.min.js"></script><script src="https://d3js.org/d3-collection.v1.min.js"></script><script src="https://d3js.org/d3-color.v1.min.js"></script><script src="https://d3js.org/d3-format.v1.min.js"></script><script src="https://d3js.org/d3-interpolate.v1.min.js"></script><script src="https://d3js.org/d3-time.v1.min.js"></script><script src="https://d3js.org/d3-time-format.v2.min.js"></script><script src="https://d3js.org/d3-scale.v1.min.js"></script>

Page 65: Codemotion 2016 - d3.js un taller divertido y difícil

cambios de nombres

v3d3.scale.linear

d3.layout.treemap

d3.scale.ordinal

d3.time.format

v4d3.scaleLinear

d3.treemap

d3.scaleOrdinal d3.scaleBands d3.scalePoints

d3.timeFormat

Page 66: Codemotion 2016 - d3.js un taller divertido y difícil

cambian los joins

v3 v4var circle = svg.selectAll("circle").data(data) // UPDATE .style("fill", "blue");

// ENTER; modifies UPDATE! 🌶circle.enter().append("circle") .style("fill", "green");

circle // ENTER + UPDATE .style("stroke", "black");

circle.exit().remove(); // EXIT

var circle = svg.selectAll("circle").data(data) // UPDATE .style("fill", "blue");

circle.enter().append("circle") // ENTER .style("fill", "green") .merge(circle) // ENTER + UPDATE .style("stroke", "black");

circle.exit().remove(); // EXIT

Page 67: Codemotion 2016 - d3.js un taller divertido y difícil

otros cambios• mejor soporte para Canvas (d3-shape)• transiciones coordinadas• muchos otros cambios menores– https://iros.github.io/d3-v4-whats-new

Page 68: Codemotion 2016 - d3.js un taller divertido y difícil

integraciónen mis apps

Page 69: Codemotion 2016 - d3.js un taller divertido y difícil

la convención de márgenesvar margin = {top: 20, right: 10, bottom: 20, left: 10};

var width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom;

var svg = d3.select("body").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

http://bl.ocks.org/mbostock/3019563

var x = d3.scale.linear() .range([0, width]); // area útil

var y = d3.scale.linear() .range([height, 0]); // area útil

Page 70: Codemotion 2016 - d3.js un taller divertido y difícil

angular.js - directivas

<div class="participacion" an-chart-participacion data-current='dataCurrent' data-prev='dataPrev'></div>

Page 71: Codemotion 2016 - d3.js un taller divertido y difícil

angular.js - directivasmodule.directive('anChartParticipacion', function(){ var _drawChart = function(elem, dataCurrent, dataPrev, options) { … // codigo d3 aquí … };

return { restrict: 'A', scope: { dataCurrent: '=current', dataPrev: '=prev', }, link: function(scope, elem) { elem.addClass('an-chart-participacion'); scope.$watchGroup(['dataCurrent','dataPrev'], function() { if( !scope.dataCurrent || !scope.dataPrev ) return;

_drawChart(elem, scope.dataCurrent, scope.dataPrev); }); }, };});

Page 72: Codemotion 2016 - d3.js un taller divertido y difícil

angular.js - directivasvar _drawChart = function(elem, dataCurrent, dataPrev, options) { elem = d3.select(elem[0]); options = _.defaults(options, { width: 50, height: 60 });

var margin = {top: 0, right: 0, bottom: 20, left: 0};

var width = options.width - margin.left - margin.right, height = options.height - margin.top - margin.bottom;

elem.select("svg").remove(); var svg = elem.append("svg") .attr("width", options.width) .attr("height", options.height) .attr("viewBox", [0, 0, options.width, options.height].join(' ')) .append('g') .attr('transform', 'translate(0, ' + margin.top + height + ') scale(1,-1)'); …}

Page 73: Codemotion 2016 - d3.js un taller divertido y difícil

Un taller de d3.js difícil y divertido*

¿qué necesitas para hacer visualizaciones de datos impresionantes?

*http://www.macwright.org/presentations/dcjq/

Javier Abadía@javierabadia

FIN

Page 74: Codemotion 2016 - d3.js un taller divertido y difícil

conceptos y ejemplos

• teoría• selecciones• data joins• svg• escalas• animación• layouts• datos anidados• adornos, tooltips, eventos• otras libs: dc.js / crossfilter• dimple

• bullets (html)– selecciones, data joins

• barras horizontales (otro más interesante?)– svg, escalas, animación

• evolución temporal– data joins (enter, exit), animación

• sectores– pie, arc

• escaños• [datos anidados]• cajamar

Page 75: Codemotion 2016 - d3.js un taller divertido y difícil

Nested data – Nested selections• selectAll().data()– selectAll().data(function(l1) { return l1.l2_items; })

• great example: http://code.hazzens.com/d3tut/lesson_3.html