Realizarea unei diagrame liniare în D3.js v. 5

a venit timpul să intensifice jocul nostru și de a crea o diagramă linie de la zero. Și nu orice diagramă liniară: un grafic cu mai multe serii care poate găzdui orice număr de linii. Pe lângă manipularea mai multor linii, vom lucra cu scări de timp și liniare, axe și etichete – sau, mai degrabă, le vom face să funcționeze pentru noi. Există o mulțime de a face, așa că vă sugerez să foc de pe serverul D3 și să trecem cracare.

vom crea această frumusețe! Distracție!

pregătirea documentelor

ca prim pas trebuie să pregătim datele și structura fișierelor pentru vizualizare. Creați line_chart.html, stiluri.css și date.csv în folderul de proiect și să le populeze cu fragmentele care urmează. Asta ne va ajuta să începem.

lipiți acest lucru în line_chart.fișier html. Codul definește elementul svg pentru noi, astfel încât să putem începe să desenăm imediat. De asemenea, am creat o structură de bază în avans, astfel încât este mai ușor să navigați în document pe măsură ce lucrăm la secțiunile sale particulare.

lăsați stilurile.document css gol pentru moment. Lipiți următoarele rânduri la date.csv. Diagrama linie va cuprinde mai multe serii: corespunzătoare coloanelor A, B și C.

date,A,B,C20-Jul-2019,10,20,1621-Jul-2019,11,22,1822-Jul-2019,13,19,2123-Jul-2019,11,17,2224-Jul-2019,15,16,2025-Jul-2019,16,19,1826-Jul-2019,19,21,1827-Jul-2019,22,25,1528-Jul-2019,18,24,1229-Jul-2019,14,20,1630-Jul-2019,14,18,1831-Jul-2019,16,18,2101-Aug-2019,15,20,2202-Aug-2019,14,21,19

pregătirea datelor

primul pas – și un pas crucial pentru întreaga vizualizare – este citirea corectă a datelor. Am folosit un exemplu cu mai multe serii dintr-un motiv: deși este destul de simplu să trasezi o singură cale, manipularea mai multor linii (în special a unui număr nedefinit dintre ele) necesită un pic mai mult de finețe D3. Lipiți următoarele în secțiunea date, reîncărcați documentul html și examinați Jurnalul consolei din browserul dvs:

const timeConv = d3.timeParse("%d-%b-%Y");const dataset = d3.csv("data.csv");dataset.then(function(data) { const slices = data.columns.slice(1).map(function(id) { return { id: id, values: data.map(function(d){ return { date: timeConv(d.date), measurement: +d }; }) }; });console.log("Column headers", data.columns);console.log("Column headers without date", data.columns.slice(1));// returns the sliced datasetconsole.log("Slices",slices); // returns the first sliceconsole.log("First slice",slices);// returns the array in the first sliceconsole.log("A array",slices.values); // returns the date of the first row in the first sliceconsole.log("Date element",slices.values.date); // returns the array's lengthconsole.log("Array length",(slices.values).length);

să trecem în revistă transformările solicitate pe setul nostru de date unul câte unul: – date.coloane returnează anteturile csv-date.coloane.slice (1) returnează anteturile csv fără coloana dată (slice începe de la coloana indexată la 1) – map () apelează o funcție pe fiecare element al matricei (constând din A, B și C) – să numim fiecare dintre aceste elemente o ‘slice’– map () atribuie numele coloanei ca element id fiecărei felii– apoi atribuie o matrice de valori fiecărei felii– rețineți modul în care elementul de valori evocă o funcție. Aici mapăm informațiile din setul de date original: matricea va consta din 2 coloane, data și măsurarea. Data este derivată din prima coloană (și transformată într-un format de dată), iar măsurarea este luată din coloana corespunzătoare cu slice-urile id.At la sfârșitul acestor transformări obținem 3 matrice: A, B și C, cu 2 coloane fiecare: data și măsurarea. Acesta este un mod uimitor de flexibil de a tăia un set de date: indiferent de câte coloane are! Totul se face în acele câteva rânduri. Am tipărit câteva informații pe consolă pentru a vă ajuta să examinați fragmentul.

Jurnalul consolei

examinați Jurnalul consolei pentru mai multe informații

pregătirea cântarelor

după ce datele au fost citite, trebuie să configurăm mecanismul de scalare. Acest lucru se face pentru a imprima graficul în conformitate cu imobilul svg. Cântarele transformă introducerea datelor (datele și valorile noastre) în coordonate pe planul svg. Lipiți următoarele linii în secțiunea scale.

const xScale = d3.scaleTime().range();const yScale = d3.scaleLinear().rangeRound();xScale.domain(d3.extent(data, function(d){ return timeConv(d.date)}));yScale.domain();

vom trasa datele de pe axa x și valorile de pe axa Y. D3 oferă o metodă scaleTime() pentru datele de scalare și o metodă scaleLinear () pentru valorile continue. Mai întâi decidem intervalul scalei: la ce ar trebui traduse valorile de intrare. În acest caz, vom întinde valorile datelor de la 0 la lățimea svg, iar valorile numerice de la înălțimea svg la 0. Ca al doilea pas, specificăm domeniul datelor de intrare. Un domeniu constă din toate valorile între un minim specificat și un maxim pe care un set de date îl poate lua. În loc de a căuta manual aceste valori, vom trece prin construit în funcții D3: – d3.măsura () returnează o valoare minimă și maximă a unui tablou (într – o ordine naturală)– acest lucru va funcționa perfect pe setul nostru de date-d3.max () returnează o valoare maximă a matricei. Rețineți Cum în acest exemplu extragem mai întâi o valoare maximă din fiecare matrice pentru a selecta apoi maximum din toate cele trei. De asemenea, am adăugat 4 la valoarea maximă din motive estetice pur subiective: am vrut să am un spațiu deasupra graficului.

cântarele sunt acum configurate. Dacă nu aveți suficiente Scale și doriți să vedeți mai multe exemple, aruncați o privire la tutorialul meu anterior.

o scară bine configurată ne permite să începem trasarea valorilor pe svg. De fiecare dată când evocăm setul de date, trebuie doar să apelăm la o scară adecvată.

axe

destul de chat – să tragem ceva deja! Axele sunt un bun punct de plecare: dacă sunt reprezentate corect, ne vor asigura că datele au fost citite așa cum era de așteptat și că se scalează la fel de frumos pe cât ne-am imaginat.

lipiți acest lucru pe axele din secțiunea pregătire:

const yaxis = d3.axisLeft().scale(yScale); const xaxis = d3.axisBottom().scale(xScale);

și asta la axe sub secțiunea de desen:

svg.append("g") .attr("class", "axis") .attr("transform", "translate(0," + height + ")") .call(xaxis);svg.append("g") .attr("class", "axis") .call(yaxis);

și la fel de simplu ca și faptul că am trasat axele X și y!

axele sunt aici!

desigur, axele nu sunt cele mai elegante din lume (există câteva axe frumoase acolo), dar sunt aici! Există câteva modificări suplimentare pe care le putem aplica pentru a le face mai prietenoase pentru cititor.

să ne uităm mai întâi la axa x: se întâmplă ceva amuzant cu datele. Citind din stânga, obținem ‘Sat 20’, ‘iulie 21’, ‘Mon 22’, și la un moment dat ajungem doar ‘August’. Se pare că lunile și zilele au venit într-un amestec insubordonat de variații. Trebuie să punem capăt acestui stil liber și prin aceasta vreau să spun că ar trebui să decidem ce format de dată dorim să imprimăm pe ecran. D3.metoda axis () ne permite să ajustăm tot felul de lucruri pentru căpușe – numărul lor, intervalul dintre puncte, formatul de afișare etc. Să configurăm unele dintre ele pentru ambele axe.

înlocuiți definiția axelor din secțiunea pregătire cu următorul fragment și reîmprospătați vizualizarea:

const yaxis = d3.axisLeft() .ticks((slices.values).length) .scale(yScale);const xaxis = d3.axisBottom() .ticks(d3.timeDay.every(1)) .tickFormat(d3.timeFormat('%b %d')) .scale(xScale);

codul de mai sus specifică un număr stabilit de căpușe pentru axa y (14 sau câte elemente de matrice / rânduri csv). În cazul axei x, o bifă va fi afișată cu o granularitate de o zi, în fiecare zi. Acest lucru a fost realizat prin setarea proprietății de bifare la d3.timeDay.fiecare (1). Formatul datelor afișate va afișa ziua și luna prescurtată pentru fiecare bifă. După aceste modificări ajungem cu axe oarecum îmbunătățite:

Ordnung, în sfârșit

datele neascultătoare nu mai sunt o problemă!

pentru a face chiar mai bine (este chiar posibil!!!) putem adăuga o etichetă pe axa y pentru a arăta ce reprezintă valorile. În timp ce datele sunt auto-explicative, numerele pe cont propriu nu conțin informații. Adăugați o etichetă (numiți-o cum doriți – am mers cu frecvență) adăugând următoarele la desenul axei y:

//this you hadsvg.append("g") .attr("class", "axis") .call(yaxis)//this you append .append("text") .attr("transform", "rotate(-90)") .attr("dy", ".75em") .attr("y", 6) .style("text-anchor", "end") .text("Frequency");

(nu există un set de stil pentru etichetă, astfel încât să nu se afișeze pe grafic – dar credeți-mă și instrumentele pentru dezvoltatori Google Chrome, este acolo)

eticheta

eticheta axei y este invizibilă

în cele din urmă, să îmbunătățim aspectul axelor. Prin îmbunătățire vreau să spun: setați culorile, lățimile și redarea fiecărui element și decideți fontul de utilizat. Lipiți următoarele în fișierul css și nu ezitați să luați propriile decizii de stil:

/* AXES *//* ticks */.axis line{stroke: #706f6f;stroke-width: 0.5;shape-rendering: crispEdges;}/* axis contour */.axis path {stroke: #706f6f;stroke-width: 0.7;shape-rendering: crispEdges;}/* axis text */.axis text {fill: #2b2929;font-family: Georgia;font-size: 120%;}

căpușele sunt controlate de .element de linie a axei, în timp ce axa reală este setată cu .element de cale. Axele arată ascuțite (opinia umilă a autorului) și sunt gata să primească câteva date:

axe Prettified

fără alte formalități, să complot diagramă!

diagrama liniei

liniile sunt în esență d3.căi () care conectează o grămadă de coordonate (X, Y) pe un plan 2D. Pentru a construi o linie, trebuie să-i spuneți unde să-și găsească coordonatele x și y și apoi să le adăugați la svg. Lipiți următoarele fragmente în substituenții creați anterior și să examinăm codul împreună.

acest lucru ar trebui să ajuns la linii de biți în secțiunea de pregătire:

const line = d3.line() .x(function(d) { return xScale(d.date); }) .y(function(d) { return yScale(d.measurement); });

în acest fragment am numit un constructor de linie, d3.linie() care utilizează doi accesori: x pentru valori pe plan orizontal și y pentru axa verticală. Aici indicăm pur și simplu cele mai granulare valori ale matricei, datei și măsurătorilor noastre (nu este momentul să vă faceți griji cu privire la structura CSV imbricată). După ce ați terminat, lipiți următoarele pe liniile de sub secțiunea desen:

const lines = svg.selectAll("lines") .data(slices) .enter() .append("g"); lines.append("path") .attr("d", function(d) { return line(d.values); });

acest lucru necesită o explicație. Liniile variabile selectează un număr neidentificat de linii din svg – și spune imediat D3 că vor exista 3 linii indicând setul de felii (liniile A, B și C). Apoi adaugă un element g fiecăruia dintre ele: un element de grupare care ne va ușura viața în timp util. Elementul g va colecta tot ce are legătură cu o anumită serie de diagrame (aka o felie din matrice): linia (reprezentată mai sus ca cale), punctele sale de date pe care le vom putea trece peste și etichetele seriei.

primul lucru pe care trebuie să-l adăugați la linii (care sunt de fapt 3 containere goale G) sunt liniile grafice în sine. Noi numim d3.linie () constructor pe datele pentru a desena o cale. Vedeți cum mai întâi trebuie să accesăm valorile de sub fiecare felie. Aceasta este apoi transmisă constructorului care trage datele și măsurătorile după cum este necesar.

după salvarea modificărilor, vizualizarea se actualizează la aceasta:

în loc de o diagramă linie avem o diagramă de munte

bine, acest lucru nu este perfect, dar crede-mă, ajungem acolo! Să aplicăm câteva corecții estetice pe diagramă și să observăm cum se formează. Adăugați următoarele stiluri.css:

/* LINE CHART */path {fill: none;stroke: #ed3700;}

trebuie să setăm umplerea la niciuna pentru ca formele să reapară ca linii. Reîmprospătați graficul:

liniile au apărut

ce separă o diagramă de linie de o grămadă de linii lipite împreună pe un grafic? Capacitatea de a diferenția între serii. În momentul de față avem doar prima.

pentru început, trebuie să facem o distincție între liniile din cod. Să adăugăm un id la fiecare clasă de linie – adăugați următoarele la secțiunea linii din partea de pregătire:

let id = 0;const ids = function () { return "line-"+id++;}

această mică bucată de cod creează un contor pe care îl putem folosi pentru a atribui automat un ID de linie fiecărei linii adăugate. Să facem referire la contor în proprietatea clasei căilor. Ajustați codul în secțiunea linii pentru a adăuga proprietatea clasei:

const lines = svg.selectAll("lines") .data(slices) .enter() .append("g"); lines.append("path") .attr("class", ids) .attr("d", function(d) { return line(d.values); });

și Magic, fiecare cale devine propria clasă!

Path class

liniilor li se dă propria identitate

ceea ce ne-a mai rămas este să facem referire la aceste clase în css și să dăm fiecărei linii propriul său caracter unic. Modificați secțiunea diagramă linie a css pentru a spune:

/* LINE CHART */path.line-0 {fill: none;stroke: #ed3700;}path.line-1 {fill: none;stroke: #2b2929;stroke-dasharray: 2;}path.line-2 {fill: none;stroke: #9c9c9c;stroke-dasharray: 6;}

observați cum nu numai că modific culoarea, ci și schimb cursa fiecărei linii. Amintiți-vă că aproximativ 10% din toți oamenii au un anumit grad de daltonism și, în toată corectitudinea, diferențierea între culori poate fi dificilă pentru oricare dintre noi. Culorile se vor amesteca doar dacă există prea multe serii de date și nuanța lor va apărea diferit pe fiecare monitor.

după ce modificările au fost aplicate, liniile să fie clar separate pe grafic-cum ar fi prezentat mai jos:

liniile sunt vizual diferite unele de altele

acum seriile sunt diferențiate, dar este încă imposibil de spus care este care, dacă nu ați memorat datele de bază și aveți o imaginație vizuală destul de bolnavă, caz în care mă întreb de ce ați avut nevoie de un grafic în primul rând. Pentru a ajuta majoritatea dintre noi în recunoașterea seriei propun să adăugăm numele seriei în partea dreaptă a graficului. Adăugați următoarele la secțiunea de desen a liniilor:

lines.append("text") .attr("class","serie_label") .datum(function(d) { return { id: d.id, value: d.values}; }) .attr("transform", function(d) { return "translate(" + (xScale(d.value.date) + 10) + "," + (yScale(d.value.measurement) + 5 ) + ")";}) .attr("x", 5) .text(function(d) { return ("Serie ") + d.id; });

fragmentul localizează sfârșitul fiecărei linii și îi adaugă un element de text. Textul va fi tipărit ca Serie A, Serie B sau Serie C, în funcție de linie. Adăugați următoarele la documentul css pentru a ajusta etichetele seriei:

.serie_label {fill: #2b2929;font-family: Georgia;font-size: 80%;}

etichetele sunt anexate! Vremuri bune.

fiecare serie a primit propria etichetă

cu toții putem fi de acord aceasta este o diagramă linie frumos! Am lipit codul complet de mai jos. Asigurați-vă că consultați a doua parte a tutorialului care prezintă două scenarii de adăugare a interactivității în diagramă.

Urmați-mă pe Twitter pentru mai multe proiecte de vizualizare a datelor / a datelor!

mostre de cod

line_chart.html:

stiluri (

styles).css:

/* AXES *//* ticks */.axis line{stroke: #706f6f;stroke-width: 0.5;shape-rendering: crispEdges;}/* axis contour */.axis path {stroke: #706f6f;stroke-width: 0.7;shape-rendering: crispEdges;}/* axis text */.axis text {fill: #2b2929;font-family: Georgia;font-size: 120%;}/* LINE CHART */path.line-0 { fill: none; stroke: #ed3700;}path.line-1 { fill: none; stroke: #2b2929; stroke-dasharray: 2;}path.line-2 { fill: none; stroke: #9c9c9c; stroke-dasharray: 6;}.serie_label { fill: #2b2929; font-family: Georgia; font-size: 80%;}

data.csv: