D3

Data Driven Documents

David García Garzón

Introducción

Objetivo

Explicar los conceptos detrás de D3.
Una librería Javascript para
representación visual de datos

Base: Javascript, SVG

Cómo se integra con nuestra pila:
Mithril, Webpack…

Librería Modular

Puedes escoger lo que cargas

Se puede ampliar vía plugins

  • d3.selection: buscar y alterar DOM
  • d3.array: manipular los datos a visualizar
  • d3.scale: mapeo datos-representación
  • d3.axis: dibujar ejes
  • d3.transition: cambios animados

Idiomas

Los setters retornan this en vez de undefined. Para poder encadenar varios setters sin mediar variables.

Convención: En una cadena de setters se desindentan los que no retornan this, para indicar que el objeto cambia.

Idiomas

API D3 usa el setter sin parámetro como getter

Ojo, fallo típico: Llamar setter con valor undefined.

d3.select('circles')
    // Error rabiox en vez de radiox
    // es undefined, y se llama como getter
    // retorna el valor actual de rx y no this
    .attr('rx', config.posx)
    // Missleading Error: 100.attr is not a function
    .attr('ry', config.poxy)

Selections

Selecciones

La base de operación de D3.

Muy parecido a JQuery. Usa selectores XPath/CSS.

d3.select(selector): first matching elements in the whole document
d3.selectAll(selector): all matching elements in the whole document
selection.select[All](selector): first/all matching child elements in selections

Modificando selecciones

// Crean elementos nuevos y los retornan
sel.append('ul'); // como último hijo
sel.insert('ul', hermano); // antes de hermano o primer hijo
sel.clone(); // replica la selección en el mismo padre
sel.remove(); // eliminan la selección
// Reordenar
sel.raise(); sel.lower(); // mueve como primer o último hijo
sel.sort(orderFunction); // reordena la selección
sel.order() // fija el orden de la selección

Modificando selecciones

// Con valor son setters, retornan la selección original
sel.attr(name, value);
sel.style('attrib' , value);
sel.classed('class1 class2', true);
sel.property('checked', value);
sel.text(text);
sel.html(htmlLiteral);

Si el valor es una función, recibe: (datum, index, nodes). this seria nodes[i].

Si no se pone valor, hace de getter, no de setter.

Integración Mithril

En el oncreate, ampliamos con D3 el nodo raiz que ha construido Mithril.

myd3widget.view = function(vn) {
    return m('svg', ...);
};
myd3widget.oncreate = function(vn) {
    var visualization = d3.select(vn.dom);
    // Rellenamos con código D3 aquí
};

Dejamos a D3 gestionar el binding de datos y las animaciones.

Integración de datos

Selecciones especiales de asociación de datos

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

circle.exit().remove(); // EXIT: elementos sin datos

circle = circle.enter() // ENTER: datos sin elementos
    .append("circle")
        .style("fill", "green")
    .merge(circle) // ENTER + UPDATE: nuevos y añadidos
        .style("stroke", "black");

Usando los datos

Podemos usar los setters pasando funciones como valor. La función se llama para cada elemento de la selección, pasando el dato asociado.

circle = circle.enter() // ENTER: datos sin elementos
    .append("circle")
        .style("stroke", function(d, i, nodes) {
            return domainFieldToStrokeScale(d.mydomainField)+'px';
        })

Control flow

Scales

Scale

Las escalas mapean valores de dominio de datos a valores de representación (posición, color, etiquetas…)

// Tipos: scaleLinear, scalePow, scaleLog, scaleOrdinal...
var scale = d3.scaleLinear()
    .domain([10, 130])
    .range([0, 960]);
// Ojo: Arrays de dos posiciones, no dos parámetros

// Son callables
scale(20); // 80
scale(50); // 320
scale.invert(80); // 20, de representación a dominio
scale.domain(); // [10, 130], getter/setter
scale.ticks(10); // 10 puntos representativos
// [ 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000 ]

Ticks

Puntos representativos (redondos)

scale.ticks(10); // 10 puntos
// [ 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000 ]
// Funcion o especificador de formato para los valores de tick
scale.tickFormat(
scale.ticks(10).map(scale.tickFormat())

scale.nice() extiende los limites del dominio a valores redondos.

Escalas Numéricas

  • Linear: x: y = mx + b
  • Pow: x: y = mx^k + b (configurable exponent)
  • Log: x: y = m log(x) + b (configurable base)
  • Identity: Alias para Linear de [0,1] a [0,1]
  • Sqrt: Alias para Pow con exponent 0.5

Por defecto, un valor fuera del intervalo/dominio se extrapola.

Si indicamos scale.clamp(), se mapea al valor extremo.

Escalas interpoladas

Se usa una funcion en vez de un intervalo de salida

Pensados para usar interpoladores de colores del paquete d3.scale-chromatic

Sequential: Dominio definido por dos valores, se mapean a 0,1 que se pasa al interpolador

Diverging: Dominio definido por tres valores, se mapean a -1, 0, 1, y se pasa al interpolador

Escalas discretas

Dominios continuos a un conjunto limitado de valores

  • Quantize: Segmentos de igual longitud en el dominio
  • Quantile: Segmentos con igual numero de elementos del domain
  • Threshold: Segmentos con umbrales arbitrarios (domain define N umbrales, range N+1 salidas)

scale.invertExtend(valorSalida) -> [inicio, fin]

Dominios Discretos

  • Ordinal: Discretos a discretos, por orden
  • Point: Discretos a puntos espaciados en el intervalo
    • Definimos padding (outer) como ratio del range
  • Band: Distribuye y expande elementos discretos en el intervalo
    • Definimos paddingInner y paddingOuter
    • Devuelve el inicio de cada banda y el bandwidth resultante

Dominio temporal

  • Time: domain is local time
  • Utc: domain is utc time

Axis

Axis

Genera SVG’s para los ejes de una gráfica.

Se basa en un scale.

var axis = d3.axisLeft/Right/Top/Bottom(scale);
axis.ticks(...); // set explicit ticks
axis.ticks(); // get the ticks

Animaciones

Transition

Movimientos suaves de un estado a otro.

// Definimos la transición a partir de una selección
var t = selection.transition('mytransition')
    // Timing de la transición
    .delay(100) // milliseconds, default 0
    .duration(6000) // milliseconds, default 250ms
    .ease(d3.easeLinear) // default d3.easeCubica
    // el módulo d3-ease contiene diversos tipos de transiciones
    // Despues decimos que parametros transicionamos
    .attr('attribute', targetValue)
    .style('attribute', targetValue)
    .text(targetText) # busca patrones numericos y los interpola
    .remove() // borra lo seleccionado cuando acabe la transición

Avanzado

t.interrupt(name);  // Para la transición
t.transition(name); // Crea una transicion sequencial a la anterior
t.select(...);  // Crea una subtransicion paralela con un
                //   subconjunto de elementos
t.selection();  // Devuelve la selección orignal (sin transición)
                //   Util para seguir con la cascada
t.merge(nodes); // Añade nodos a la transición
t.on('start', callback)
                // Llama el callback cuando empiece la transicion
                // Tambien 'end' y 'interrupt'

Tweening

Cuando los interpoladores por defecto no bastan

transition
    // Llamadas equivalentes
    .style('fill', 'blue') // por defecto
    .styleTween("fill", function() {
        // podriamos escoger otro del módulo d3-interpolate
        return d3.interpolateRgb(this.style.fill, "blue");
    });
    // O nuestro propio interpolador
    .attrTween('attribute', function() {
        // Initialization here
        return function(t) {
            // t is 0 to 1 point from the ease
            return computedAttrValue;
        }
    }

Otros módulos

Infrastructura básica

  • d3-selection: Busqueda y manejo en bloque de elementos del dom a partir de selectores css
  • d3-transition: TODO
  • d3-scale: Abstrae correspondencias entre datos y representación

Interacción

  • d3-axis: Ejes de coordenadas según una escala
  • d3-brush: Selector de rango uni o bidireccional
  • d3-zoom: Maneja transformaciones de panning y zoom
  • d3-drag: Gestionar eventos de drag and drop

Datos dominio

  • d3-fetch: Load external data (json, dsv, binary, xml…)
  • d3-dsv: Cargador de Delimiter Separated Values (CSV, TSV…)
  • d3-array: Augmenta los métodos de array: estadisticos, busqueda, histogramas, transformación…
  • d3-collection: Mapas, Conjuntos con api mas guai y Nests (datos anidados)
  • d3-hierarchy: Navegación en estructuras jerarquicas y varios tipos de visualizaciones

Visualizaciones

  • d3-shape: Dibuja Tartas, sectores, linieas punteadas, curvas, areas, linieas de enlace, barras apiladas…
  • d3-polygon: Cálculos con poligonos: area, perímetro, centroide, inclusion, casco convexo
  • d3-color: Manipulacion de colores en varios espacios cromáticos
  • d3-geo: Como polygon pero en geodesicas, y transforma a diversas proyecciones, carga geojson
  • d3-contour: Genera diagramas de controrno sobre datos, dispersiones y funciones 2D
  • d3-voronoi: Genera diagramas de voronoi
  • d3-chord: Genera diagramas de cuerdas (relaciones entre elementos en un circulo)
  • d3-force: Anima posiciones de los nodos simulando fuerzas: de enlace, campos, direccionales, radiales…

Otros

  • d3-dispatch: Mecanismo de signal-slot

  • d3-timer: Temporizador pensado para funcionar con animaciones

  • d3-ease: Libreria de funciones de transición

  • d3-scale-chromatic: Libreria de escalas de color

  • d3-random: Generar diversas distribuciones

  • d3-interpolate: Métodos de interpolación entre diversos tipos de objetos: numeros, colores, curvas…

  • d3-format: Number formating

  • d3-time: Operaciones convenientes para tiempo

  • d3-time-format: Date/Time formating

  • d3-path: Permite reusar codigo canvas para generar svg d3 compatible

  • d3-quadtree: Divide y venceras para optimizar busquedas multidimensionales

d3.color

Manipulacion de color.

d3.collections

Map, Set y Nest

Nest esta pensado para hacer ‘group by’.

d3.ease

Contiene tipos de curbas de transición

d3.