de Déborah Mesquita

O introducere ușoară la D3: cum să construiți un grafic cu bule reutilizabile

Noțiuni introductive despre D3

O introducere usoara la D3 cum sa construiti un grafic

Când am început să învăț D3, nimic nu avea sens pentru mine. Lucrurile au devenit mai clare doar când am început să aflu despre diagramele reutilizabile.

În acest articol, vă voi arăta cum să creați o diagramă cu bule reutilizabile și să vă ofer o introducere ușoară a D3 pe parcurs. Setul de date pe care îl vom folosi este compus din povești publicate în Routech în ianuarie 2017.

O introducere usoara la D3 cum sa construiti un grafic
Acesta este graficul pe care îl veți construi

Despre D3

D3 este o bibliotecă JavaScript pentru vizualizarea datelor. Acesta dă viață datelor folosind HTML, SVG și CSS.

De multe ori trebuie să refolosim o diagramă într-un alt proiect sau să împărtășim graficul cu alții. Pentru aceasta, Mike Bostock (creatorul D3) a propus un model numit diagrame refolosibile. Vom folosi abordarea sa cu câteva mici modificări, așa cum este prezentat de Pablo Navarro Castillo în carte Stăpânirea D3.js.

Folosim versiunea D3 4.6.0 Aici.

? Diagrame refolosibile

Graficele care urmează modelul grafic reutilizabil au două caracteristici:

  • Configurabilitate. Vrem să modificăm aspectul și comportamentul graficului fără a trebui să modificăm codul în sine.
  • Abilitatea de a fi construit într-un mod independent. Vrem fiecare element grafic asociat cu un punct de date al setului nostru de date în mod independent. Acest lucru are legătură cu modul în care D3 asociază instanțele de date cu elementele DOM. Acest lucru va deveni mai clar într-un minut.

„Pentru a rezuma: implementați diagrame ca închideri cu metode getter-setter. ” – Mike Bostock

Graficul cu bule

Mai întâi trebuie să definiți ce elemente ale graficului pot fi personalizate:

  • Dimensiunea graficului
  • Setul de date de intrare

Definirea dimensiunii graficului

Să începem prin a crea o funcție care să încapsuleze toate variabilele grafului și să setăm valorile implicite. Această structură se numește închidere.

// bubble_graph.js
var bubbleChart = function () {    var width = 600,    height = 400;    function chart(selection){        // you gonna get here    }    return chart;}

Doriți să creați diagrame de diferite dimensiuni fără a fi nevoie să modificați codul. Pentru aceasta, veți crea diagrame după cum urmează:

// bubble_graph.html
var chart = bubbleChart().width(300).height(200);

Pentru a face acest lucru, acum veți defini accesorii pentru variabilele de lățime și înălțime.

// bubble_graph.js
var bubbleChart = function () {    var width = 600    height = 400;
    function chart(selection){        // we gonna get here    }    chart.width = function(value) {        if (!arguments.length) { return width; }        width = value;        return chart;    }
    chart.height = function(value) {        if (!arguments.length) { return height; }        height = value;        return chart;    }    return chart;}

Dacă suni bubbleChart() (fără atribute de lățime sau înălțime) graficul este creat cu valorile implicite pentru lățime și înălțime definite în interiorul închiderii. Dacă este apelată fără argumente, metoda returnează valoarea variabilei.

// bubble_graph.html
var chart = bubbleChart();bubbleChart().width(); // returns 600

Este posibil să vă întrebați de ce metodele returnează funcția grafic. Acesta este un model JavaScript folosit pentru a simplifica codul. Se numește înlănțuirea metodelor. Cu acest model puteți crea obiecte noi ca acesta:

// bubble_graph.html
var chart = bubbleChart().width(600).height(400);

în loc de:

// bubble_graph.html
var chart = bubbleChart(); chart.setWidth(600); chart.setHeight(400);

Alăturarea datelor cu graficul nostru

Acum, să învățăm cum să îmbinați datele cu elementele grafice. Iată cum este structurată graficul: divul cu graficul are un element SVG și fiecare punct de date corespunde unui cerc din grafic.

O introducere usoara la D3 cum sa construiti un grafic
// bubble_graph.html, after the bubbleChart() function is called
<svg width="600" height="400">;    <circle></circle> // a story from data    <circle></circle&gt; // another story from data    ...</svg>

? d3.data ()

d3.selection.data([data[,key]]) funcția returnează o nouă selecție care reprezintă un element legat cu succes de date. Pentru a face acest lucru, trebuie mai întâi să încărcați datele din fișierul .csv. Veți folosi d3.csv(url[[, row], callback]) funcţie.

// bubble_graph.html
d3.csv('file.csv', function(error, our_data) {    var data = our_data; //here you can do what you want with the data}
// medium_january.csv|                title                 |   category   | hearts ||--------------------------------------|--------------|--------|| Nobody wants to use software         | Development  |  2700  |  | Lossless Web Navigation with Trails  |    Design    |  688   |   | The Rise of the Data Engineer        | Data Science |  862   |

? d3-selecție

Veți folosi d3-select () si date() funcții pentru a ne transmite datele în grafic.

Selecțiile permit transformarea puternică bazată pe date a modelului de obiect document (DOM): set atribute, stiluri, proprietăți, HTML sau text conținut și multe altele. – Documentația D3

// bubble_graph.html
<div class="chart-example" id="chart"><svg></svg></div>
d3.csv('medium_january.csv', function(error, our_data) {    if (error) {        console.error('Error getting or parsing the data.');        throw error;    }
    var chart = bubbleChart().width(600).height(400);    d3.select('#chart').data(our_data).call(chart);
 });

Un alt selector important este d3.selectAll (). Să presupunem că aveți următoarea structură:

<body>    <div></div>    <div></div>    <div></div></body>

d3.select("body").selectAll("div") selectează toate acele divs pentru noi.

?? d3.enter ()

Și acum veți afla despre o funcție D3 importantă: d3.enter (). Să presupunem că aveți o etichetă de corp goală și o matrice cu date. Doriți să parcurgeți fiecare element al matricei și să creați un nou div pentru fiecare element. Puteți face acest lucru cu următorul cod:

<!-- before --><body> //empty</body>
----// js script
var our_data = [1, 2, 3]var div = d3.select("body") .selectAll("div") .data(our_data) .enter() .append("div");---
<!-- after --><body>    <div></div>    <div></div>    <div></div></body>

De ce ai nevoie selectAll("div") dacă divizorii nici măcar nu există încă? Pentru că în D3 în loc să povestească Cum să facem ceva, spunem noi ce noi vrem.

În acest caz, doriți să asociați fiecare div cu un element al matricei. Asta spui cu selectAll("div").

var div = d3.select("body") .selectAll("div") // here you are saying 'hey d3, each data element      of the array that comes next will be bound to a div' .data(our_data) .enter().append("div");

enter() returnează selecția cu datele legate de elementul matricei. Apoi adăugați în cele din urmă această selecție la DOM cu ajutorul .append("div")

? d3.forceSimulation ()

Ai nevoie de ceva pentru a simula fizica cercurilor. Pentru aceasta veți folosi d3.forceSimulation([nodes]). De asemenea, trebuie să spuneți ce fel de forță va schimba poziția sau viteza nodurilor.

În cazul nostru, vom folosi d3.forceManyBody().

// bubble_chart.js
var simulation = d3.forceSimulation(data) .force("charge", d3.forceManyBody().strength([-50])) .force("x", d3.forceX()) .force("y", d3.forceY()) .on("tick", ticked);

O valoare de rezistență pozitivă determină nodurile să se atragă reciproc, în timp ce o valoare de rezistență negativă determină respingerea reciprocă.

1612063152 597 O introducere usoara la D3 cum sa construiti un grafic
Efectul force ()

Totuși, nu vrem ca nodurile să se răspândească prin întreg spațiul SVG, așa că le folosim d3.forceX(0) șid3.forceY(0). Aceasta „trage” cercurile în poziția 0. Continuați și încercați să eliminați acest lucru din cod pentru a vedea ce se întâmplă.

Când reîmprospătați pagina, puteți vedea că cercurile se ajustează până când se stabilizează în cele din urmă. ticked() funcția actualizează pozițiile cercurilor. d3.forceManyBody() actualizează continuu poziția x și y a fiecărui nod și ticked() funcția actualizează DOM cu aceste valori (atributele cx și cy).

// bubble_graph.js
function ticked(e) {    node.attr("cx", function(d) { return d.x; })        .attr("cy", function(d) { return d.y; });    // 'node' is each circle of the bubble chart
 }

Iată codul cu totul împreună:

var simulation = d3.forceSimulation(data)     .force("charge", d3.forceManyBody().strength([-50]))     .force("x", d3.forceX())     .force("y", d3.forceY())     .on("tick", ticked); 
function ticked(e) {     node.attr("cx", function(d) { return d.x; })         .attr("cy", function(d) { return d.y; }); }

Pentru a rezuma, tot ce face această simulare este de a da fiecărui cerc o poziție x și y.

? d3.scale

Aici vine partea cea mai interesantă: adăugarea de fapt a cercurilor. Amintiți-vă introduce() funcţie? Îl vei folosi acum. În graficul nostru, raza fiecărui cerc este proporțională cu numărul de recomandări din fiecare poveste. Pentru a face acest lucru, veți utiliza o scară liniară: d3.scaleLinear ()

Pentru a utiliza scale trebuie să definiți două lucruri:

  • Domeniu: valorile minime și maxime ale datelor de intrare (în cazul nostru, numărul minim și maxim de recomandări). Pentru a obține valorile minime și maxime, veți utiliza fișierul d3.min () și d3.max () funcții.
  • Gamă: valorile de ieșire minime și maxime ale scalei. În cazul nostru, dorim cea mai mică rază de dimensiunea 5 și cea mai mare rază de dimensiunea 18.
// bubble_graph.js
var scaleRadius = d3.scaleLinear()            .domain([d3.min(data, function(d) { return +d.views; }),                     d3.max(data, function(d) { return +d.views; })])            .range([5,18]);

Și apoi creați în cele din urmă cercurile:

// bubble_graph.js
var node = svg.selectAll("circle")   .data(data)   .enter()   .append("circle")   .attr('r', function(d) { return scaleRadius(d.views)})});

Pentru a colora cercurile, veți utiliza o scară categorică: d3.scaleOrdinal (). Această scară returnează valori discrete.

Setul nostru de date are 3 categorii: Proiectare, Dezvoltare și Știința datelor. Veți mapa fiecare dintre aceste categorii la o culoare. d3.schemeCategory10 ne oferă o listă de 10 culori, ceea ce este suficient pentru noi.

// bubble_graph.js
var colorCircles = d3.scaleOrdinal(d3.schemeCategory10);var node = svg.selectAll("circle")    .data(data)    .enter()    .append("circle")    .attr('r', function(d) { return scaleRadius(d.views)})    .style("fill", function(d) { return colorCircles(d.category)});

Vrei ca cercurile să fie desenate în mijlocul SVG, așa că vei muta fiecare cerc în mijloc (jumătate din lățime și jumătate din înălțime). Continuați și eliminați acest lucru din cod pentru a vedea ce se întâmplă.

// bubble_graph.js
var node = svg.selectAll("circle") .data(data) .enter() .append("circle") .attr('r', function(d) { return scaleRadius(d.views)}) .style("fill", function(d) {return colorCircles(d.category)}) .attr('transform', 'translate(' + [width / 2, height / 2] + ')');

Acum veți adăuga sfaturi de instrumente în grafic. Trebuie să apară ori de câte ori așezăm mouse-ul peste cercuri.

var tooltip = selection .append("div") .style("position", "absolute") .style("visibility", "hidden") .style("color", "white") .style("padding", "8px") .style("background-color", "#626D71") .style("border-radius", "6px") .style("text-align", "center") .style("font-family", "monospace") .style("width", "400px") .text("");
var node = svg.selectAll("circle") .data(data) .enter() .append("circle") .attr('r', function(d) { return scaleRadius(d.views)}) .style("fill", function(d) {return colorCircles(d.category)}) .attr('transform', 'translate(' + [width / 2, height / 2] + ')') .on("mouseover", function(d){     tooltip.html(d.category +"<br>"+ d.title+"<br>"+d.views);      return tooltip.style("visibility", "visible");}) .on("mousemove", function(){   return tooltip.style("top", (d3.event.pageY-       10)+"px").style("left",(d3.event.pageX+10)+"px");}) .on("mouseout", function(){return tooltip.style("visibility", "hidden");});

mousemove urmează cursorul când mouse-ul se mișcă. d3.event.pageX și d3.event.pageY returnează coordonatele mouse-ului.

Si asta e! Puteți vedea codul final Aici.

Vă puteți juca cu graficul cu bule Aici.

Ați găsit util acest articol? Încerc tot posibilul să scriu în fiecare lună un articol de scufundare profundă, poți primesc un e-mail când public unul nou.

Aveți întrebări sau sugestii? Lasă-le în comentarii. Mulțumesc pentru lectură! ?

Mulțumiri speciale lui John Carmichael și Alexandre Cisneiros.