D3


ESIPE

@comeetie, a partir d'une présentation de mbostock traduction et d3.v5

Visualisation interactive

HTML,CSS,JS

+ SVG

+ D3


D3 : Data Driven Documents

JQuerry pour le svg

Cours

M. Bostock tutorial

References

Visualisation de données avec des les standards du web

D3 aide a construire des visualisation il n'en propose pas de toute faite.

D3 utilise les standards HTML, CSS, SVG et canvas.

DataElements

Visualisation = visual encoding
(mapper des données à des éléments).

Visualiser = construire un DOM a partir des données et le maintenir si les données change ou pour répondre a des interractions de l'utilisateur.

Idée : chaque données est associé a un élément graphique (une marque) !

Data-Driven Documents

“D3” fait référence au W3C Document Object Model.

Standard Web

Plein de ressources.

“apprendre D3” c'est travailler avec les standards du web. Plein de ressources pour apprendre ces standards!

HTML Resources

HTML5 Spec, HTML5 for Developers, MDN, Dive Into HTML5

<!DOCTYPE html>
<meta charset="utf-8">
<body>
Hello, world!

SVG Resources

SVG Spec, MDN, D3 API Reference

SVG : Scalable Vector Graphics

<!DOCTYPE html>
<meta charset="utf-8">
<svg width="960" height="500">
  <circle cx="126" cy="100" style="fill:#5af15a;stroke:#555;stroke-width:5" >
  </circle>
</svg>

CSS Resources

CSS Spec, Selectors Spec

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body { background: steelblue; }
</style>
<body>
Hello, world!

JavaScript Resources

MDN, Douglas Crockford’s ES6

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script>
console.log("Hello, world!");
</script>

Getting Started

http://d3js.org/

<!DOCTYPE html>
<meta charset="utf-8">
<style>/* CSS */</style>
<body>
<script src="d3.v5.js"></script>
<script>/* JavaScript */</script>
> python -m http.server 8888 &

Developer Tools
⌥⌘I

JavaScript Console
⌥⌘J

D3 Resources

D3 API Reference, D3 Wiki, D3 Group, D3 Stack Overflow

Selections

Selection = l'élements de base en d3 // jQuerry.

Selectors

CSS fourni une syntaxe eficace de sélection

pre, code {
  font-family: "Menlo", monospace;
  font-size: 48px;
}

CSS assigne des rêgles de style via des selecteurs.

#foo        // <any id="foo">
foo         // <foo>
.foo        // <any class="foo">
[foo=bar]   // <any foo="bar">
foo bar     // <foo><bar></foo>

Sélecteurs simples

foo.bar     // <foo class="bar">
foo#bar     // <foo id="bar">

Sélecteurs composés.

Selections = tableau

d3.selectAll("pre, code")
// select all <circle> elements
var circle = d3.selectAll("circle");
// set some attributes and styles
circle.attr("cx", 20);
circle.attr("cy", 12);
circle.attr("r", 24);
circle.style("fill", "red");

les méthodes attr, style permettent de modifier attributs et le style.

// select all <circle> elements
// and set some attributes and styles
d3.selectAll("circle")
    .attr("cx", 20)
    .attr("cy", 12)
    .attr("r", 24)
    .style("fill", "red");

Enchainement de méthode

selection.append

Création de nouveaux éléments et ajout.

select ≠ selectAll

Select only the first, or select them all.

Append

// select the <body> element
var body = d3.select("body");

// add an <h1> element
var h1 = body.append("h1");
h1.text("Hello!");

Si la sélection est unitaire ajoute un nouvel élément

Append

// select all <section> elements
var section = d3.selectAll("section");

// add an <h1> element to each
var h1 = section.append("h1");
h1.text("Hello!");

Si la sélection contient plusieurs éléments,ajoute un nouvel éléments a chacun.

var h1 = d3.selectAll("section")
    .style("background", "steelblue")
  .append("h1") // new selection from here
    .text("Hello!");

! en cas de chainage après un "append" c'est une nouvelle sélection que l'on manipule!

Data

Data = Tableau

// A bar chart, perhaps?
var data = [1, 1, 2, 3, 5, 8];
// A scatterplot, perhaps?
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},
  {x: 11.0, y: 9.26}
];

DataElements

svg.selectAll("circle")
    .data(data)
  .enter().append("circle")
    .attr("cx", x)
    .attr("cy", y)
    .attr("r", 2.5);

“circle” ↦ data.

var circle = svg.selectAll("circle")
    .data(data);

La méthode data va permettre de faire la jointure entre données et éléments du DOM

var circle = svg.selectAll("circle")
    .data(data);

circle.enter().append("circle");

Append + enter selection créer les élemtns manquants.

var circle = svg.selectAll("circle")
    .data(data);

circle.enter().append("circle")
    .attr("cx", d => d.x)
    .attr("cy", d => d.y)
    .attr("r", 2.5);

Les nouveaux éléments sont liés aux données on peut donc modifier leurs attributs en fonction d'elles !

Enter, Update & Exit

DataElements

Joins

Enter

DataElements

Nouvelles données data sans éléemtns graphique associés.

var circle = svg.selectAll("circle")
    .data(data)
  .enter().append("circle")
    .attr("cx", x)
    .attr("cy", y)
    .attr("r", 2.5);

Update

DataElements

Données jointes a un élemnts graphique déjà existant.

var circle = svg.selectAll("circle")
    .data(data)
    .attr("cx", x)
    .attr("cy", y)
    .attr("r", 2.5);

Exit

DataElements

Elèments graphique plus attachés a des données.

exit + remove
// A scatterplot, perhaps?
var data = [
  {name: "Alice", x: 10.0, y: 9.14},
  {name:   "Bob", x:  8.0, y: 8.14},
  {name: "Carol", x: 13.0, y: 8.74},
  {name:  "Dave", x:  9.0, y: 8.77},
  {name: "Edith", x: 11.0, y: 9.26}
];

If needed, data should have a unique key for joining.

function key(d) { return d.name; }

var circle = svg.selectAll("circle")
    .data(data, key)
    .attr("cx", x)
    .attr("cy", y)
    .attr("r", 2.5);

The key function returns a unique string for each datum.

Loading Data

D3 provides several convenience routines using XMLHttpRequest.

CSV

Comma-Separated Values: d3.csv

symbol,date,price
S&P 500,Jan 2000,1394.46
S&P 500,Feb 2000,1366.42
S&P 500,Mar 2000,1498.58
S&P 500,Apr 2000,1452.43
S&P 500,May 2000,1420.6
S&P 500,Jun 2000,1454.6
S&P 500,Jul 2000,1430.83
var format = d3.time.format("%b %Y");

promises = [d3.json('./europe.json'),d3.csv("./stocks.csv")]
Promise.all(promises).then( function(stocks) {
  stocks.forEach(function(d) {
    d.price = +d.price;
    d.date = format.parse(d.date);
  });
});

CSV pas typé, ! conversion depuis chaîne de caractères.

var format = d3.time.format("%b %Y");

promises = [d3.json('./europe.json'),d3.csv("./chomage.csv")]
Promise.all(promises).then( function(data) {
  let chomage = data[1];
  chomage.forEach(function(d) {
    d.price = +d.price;
    d.date = format.parse(d.date);
  });
});

CSV pas typé, ! conversion depuis chaîne de caractères.

! Asynchrone

array.
{filter,map,sort,…}

JavaScript built-in array methods.

d3.
{nest,keys,values,…}

D3 data-transform methods; voir API.

Scales & Axes

Scales

DataAttributes

Les attributs (et les styles) permettentde contrôler la position et l'apparence des objets créer.

DomainRange

Scales = fonctions
f : data-space ↦ visual-space.

function x(d) {
  return d * 42 + "px";
}

Quantitative Scales

continuous (numeric) domain ↦ continuous range.

var x = d3.scaleLinear()
    .domain([12, 24])
    .range([0, 720]);

x(16); // 240

linear scale = translation + mise a l'échelle

d3.min, d3.max, d3.extent pour définir le domaine !

var x = d3.scale.log()
    .domain(d3.extent(numbers))
    .range([0, 720]);
var x = d3.scaleSqrt()
    .domain([12, 24])
    .range([0, 720]);

x(16); // 268.9056992603583

Sqrt scale = transformation exponentielle

! rayon d'un cercle

Interpolation

Les échelles quantitative en d3 gère plusieur type d'interpolation suivant les valeurs du range
! ex couleurs

var x = d3.scaleLinear()
    .domain([12, 24])
    .range(["steelblue", "brown"]);

x(16); // #666586
! changement de d'espace de couleur pour l'interpolation
var x = d3.scale.linear()
    .domain([12, 24])
    .range(["steelblue", "brown"])
    .interpolate(d3.interpolateHsl);

x(16); // #3cb05f

Diverging Scales

var x = d3.scaleLinear()
    .domain([-10, 0, 100])
    .range(["red", "white", "green"]);

x(-5); // #ff8080
x(50); // #80c080

Ordinal Scales

Map discrete domain ↦ discrete range.

var x = d3.scaleOrdinal()
    .domain(["A", "B", "C", "D"])
    .range([0, 10, 20, 30]);

x("B"); // 10
var x = d3.scaleCategory20()
    .domain(["A", "B", "C", "D"]);

x("B"); // #aec7e8

Ordinal scales : couleurs / catégories.

Axes

Fonction pour aider à créer des axes et les labelisés

var yAxis = d3.axisLeft(y) 

Créer un axe pour une échelle y

svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);
.axis path, .axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

Customisation via CSS.

Ticks

var x = d3.scaleLinear()
    .domain([12, 24])
    .range([0, 720]);

x.ticks(5); // [12, 14, 16, 18, 20, 22, 24]

translate(left,top)origin

SVG Coordinates

origine ⟨0,0⟩ = top-left corner!

Trsnform pour changer d'origine

var svg = d3.select("body").append("svg")
    .attr("width", outerWidth)
    .attr("height", outerHeight);

var g = svg.append("g")
    .attr("transform", "translate("
      + marginLeft + ","
      + marginTop + ")");

SVG Basic Shapes

SVG Spec

<rect
    x="0"
    y="0"
    width="0"
    height="0"
    rx="0"
    ry="0">

Rect

<circle
    cx="0"
    cy="0"
    r="0">

Circle

<line
    x1="0"
    y1="0"
    x2="0"
    y2="0">

Line

<text
    x="0"
    y="0"
    dx="0"
    dy="0"
    text-anchor="start">

Text

SVG Paths

SVG Spec

<path d="M152.64962091501462,320.5600780855698L133.88913955606318,325.4363177123538L134.96890954443046,330.37917634921996L131.19348249532786,331.158393614812L98.56681109628815,335.53933807857004L91.14450799488135,333.79662025279L72.1880101321918,333.74733970068166L69.51723455785742,332.8569681440152L62.37313911354066,333.2100666843387L62.248334309137434,335.3677272708405L58.843440998888326,335.0574959605036L53.97667317214221,331.36075125633175L56.30952738118711,325.9417994311851L63.80207296237137,326.0219658098969L68.37010032001055,321.68160223702955L68.82177412097933,318.08112591435287L73.34…">

Paths mini-language!

Path Generators

d3.line

var x = d3.scaleLinear(),
    y = d3.scaleLinear();

var line = d3.line()
    .x(function(d) { return x(d.x); })
    .y(function(d) { return y(d.y); });
svg.append("path")
    .datum(objects)
    .attr("class", "line")
    .attr("d", line);

d3.area

var x = d3.scaleLinear(),
    y = d3.scaleLinear();

var area = d3.area()
    .x(function(d) { return x(d.x); })
    .y0(height)
    .y1(function(d) { return y(d.y); });

Et plein d'autres choses..

Réaliser une visualisation des taux de chomage dans les pays européens en utilisants les fichiers disponnible ici

Une correction pas à pas est disponnible. Les sources des différentes étapes sont disponnibles dans le répertoire html de la séance.