Egy gyengéd bevezetés a D3-hoz: hogyan lehet felépíteni egy újrafelhasználható buborékdiagramot

Az első lépések a D3-mal

Amikor elkezdtem tanulni a D3-at, semmit sem értett számomra. A dolgok csak akkor világossá váltak, amikor elkezdtem tanulni az újrafelhasználható táblázatokon.

Ebben a cikkben megmutatom, hogyan hozhat létre újrafelhasználható buborékdiagramot, és az út során gyengéd bevezetést nyújt a D3-hoz. Az általunk használt adatkészlet a freeCodeCamp alkalmazásban, 2017 januárjában közzétett történetekből áll.

Ezt a diagramot fogja készíteni

A D3-ról

A D3 egy JavaScript könyvtár az adatok megjelenítéséhez. Az adatokat életre kelti HTML, SVG és CSS használatával.

Gyakran szükségünk van egy diagram újra felhasználására egy másik projektben, vagy az esemény megosztására a diagramot másokkal. Ehhez Mike Bostock (a D3 alkotója) újrahasznosítható diagramoknak nevezett modellt javasolt. Néhány apró módosítással alkalmazzuk az ő megközelítését, amint azt Pablo Navarro Castillo ismerteti a Mastering D3.js könyvben.

Itt a D3 4.6.0 verzióját használjuk.

Tartható diagramok

Az újrafelhasználható diagrammintát követő grafikonok két jellemzővel rendelkeznek:

  • Konfigurálhatóságot. Módosítani akarjuk a grafikon megjelenését és viselkedését anélkül, hogy magának a kódnak lennie kellene.
  • Képesség független módon építeni. Szeretnénk, ha az adatkészletünk egy adatpontjához társított minden gráf elem külön lenne. Ennek köze van ahhoz, hogy a D3 miként társítja az adatpéldányokat a DOM elemekkel. Ez egy perc alatt világosabbá válik.
„Összefoglalva: a táblázatokat zárásokként hajtjuk végre getter-setter módszerekkel.” - Mike Bostock

A buborékdiagram

Először meg kell határoznia a diagram azon elemeit, amelyek testreszabhatók:

  • A diagram mérete
  • A bemeneti adatkészlet

A diagram méretének meghatározása

Kezdjük azzal, hogy létrehozunk egy függvényt, amely beilleszti a grafikon összes változóját és beállítja az alapértelmezett értékeket. Ezt a szerkezetet bezárásnak nevezik.

// bubble_graph.js
var bubbleChart = function () {
    var szélessége = 600,
    magasság = 400;

    függvénytábla (kiválasztás) {
        // ide fogsz jönni
    }

    visszatérési diagram;
}

Különböző méretű táblákat szeretne létrehozni anélkül, hogy meg kellene változtatnia a kódot. Ehhez az alábbiak szerint hozhat létre táblázatokat:

// bubble_graph.html
var chart = bubbleChart () szélesség (300) magasság (200);

Ehhez most meg kell határoznia a szélesség és a magasság változóinak elérőit.

// bubble_graph.js
var bubbleChart = function () {
    var szélessége = 600
    magasság = 400;
    függvénytábla (kiválasztás) {
        // ide fogunk jutni
    }

    chart.width = függvény (érték) {
        if (! arguments.length) {visszatérési szélesség; }
        szélesség = érték;

        visszatérési diagram;
    }
    chart.height = függvény (érték) {
        if (! arguments.length) {visszatérési magasság; }
        magasság = érték;

        visszatérési diagram;
    }

    visszatérési diagram;
}

A bubbleChart () hívására (szélesség vagy magasság attribútumok nélkül) a grafikon jön létre az alapértelmezett szélesség és magasság értékekkel, amelyeket a bezárás során definiált. Ha argumentumok nélkül hívják meg, akkor a metódus a változó értékét adja vissza.

// bubble_graph.html
var chart = bubbleChart ();
bubbleChart (). szélesség (); // 600-at ad vissza

Kíváncsi lehet, hogy a metódusok miért adják vissza a diagram funkciót. Ez egy JavaScript-minta, amely a kód egyszerűsítésére szolgál. Úgy hívják, hogy módszer láncol. Ezzel a mintával új objektumokat hozhat létre, mint például:

// bubble_graph.html
var chart = bubbleChart () szélesség (600) magasság (400);

ahelyett:

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

Adatok összekapcsolása a diagrammal

Most tanuljuk meg, hogyan lehet az adatokat diagram elemekkel összekapcsolni. A diagram felépítése a következő: a div oszlopban a grafikon SVG elemmel rendelkezik, és minden adatpont megfelel a diagram körének.

// bubble_graph.html, a bubbleChart () függvény meghívása után

      // egy történet az adatokból
      // egy másik történet az adatokból
    ...

3. d3.data ()

A d3.selection.data ([adatok [, gomb]]) függvény egy új választást ad vissza, amely egy elemhez sikeresen kötődik. Ehhez először be kell töltenie az adatokat a .csv fájlból. A d3.csv (URL [[, sor], visszahívás]) funkciót fogja használni.

// bubble_graph.html
d3.csv ('file.csv', funkció (hiba, mi_adataink) {
    var data = mi_adataink; // itt megteheti, amit akar, az adatokkal
}
// medium_january.csv
| cím | kategória | szív |
| -------------------------------------- | ---------- ---- | -------- |
| Senki sem akarja használni a szoftvert Fejlesztés | 2700 |
| Veszteség nélküli navigáció nyomvonalakkal | Design | 688 |
| Az adatmérnök felemelkedése Adattudomány | 862 |

🖍 d3-választás

A d3-select () és az data () függvényeket használja az adatok továbbításához a diagramhoz.

A választások lehetővé teszik a dokumentum-objektummodell (DOM) erőteljes adatvezérelt átalakítását: attribútumok, stílusok, tulajdonságok, HTML vagy szöveges tartalom beállítása és még sok más. - D3 dokumentáció
// bubble_graph.html
d3.csv ('medium_january.csv', funkció (hiba, mi_adataink) {
    if (hiba) {
        console.error ('Hiba történt az adatok beszerzése vagy elemzése során.');
        dobási hiba;
    }
    var chart = bubbleChart () szélesség (600) magasság (400);
    d3.select (# chart). adat (our_data) .call (chart);
 });

Egy másik fontos választó a d3.selectAll (). Tegyük fel, hogy a következő szerkezettel rendelkezik:


    
    
    

d3.select ("test"). selectAll ("div") mindazokat a divs értékeket választja ki nekünk.

3. d3.enter ()

És most megtudhatja egy fontos D3 funkciót: d3.enter (). Tegyük fel, hogy van egy üres törzscímkéje és tömb adataival. Menjen át a tömb minden elemén, és hozzon létre új elemet minden elemhez. Ezt megteheti a következő kóddal:



 //üres
----
// js szkript
var our_data = [1, 2, 3]

var div = d3.select ("test")
 .selectAll ( "div")
 .data (our_data)
 .belép()
 .append ( "div");

---


    
    
    

Miért van szüksége a selectAll ("div") -re, ha a div-ok még nem léteznek? Mivel a D3-ban ahelyett, hogy elmondnánk, hogyan kell csinálni valamit, azt mondjuk, amit akarunk.

Ebben az esetben minden div-t társítani kell a tömb elemével. Ez az, amit a selectAll ("div") -el mond.

var div = d3.select ("test")
 "
 .data (our_data)
 .enter (). append ( "div");

Az enter () visszaadja a választást az adatokhoz kötött adatokkal a tömb eleméhez. Ezután végül hozzáadja ezt a választást a DOM-hoz a .append ("div") segítségével

d3.forceSimulation ()

Szüksége van valamire a körök fizikájának szimulálására. Ehhez a d3.forceSimulation ([csomópontok]) parancsot fogja használni. Azt is el kell mondania, hogy milyen erő változtatja meg a csomópontok helyzetét vagy sebességét.

Esetünkben a d3.forceManyBody () -ot fogjuk használni.

// bubble_chart.js
var szimuláció = d3.forceSimulation (adatok)
 .force ("töltés", d3.forceManyBody (). erő ([- 50]))
 .force ("x", d3.forceX ())
 .force ("y", d3.forceY ())
 .on ("kullancs", pipálva);

A pozitív szilárdsági érték miatt a csomópontok vonzzák egymást, míg a negatív szilárdsági érték meghiúsítja egymást.

Az erő () hatás

Nem akarjuk, hogy a csomópontok elterjedjenek az egész SVG térben, ezért használjuk a d3.forceX (0) és a d3.forceY (0) fájlokat. Ez "körbehúzza" a köröket 0 helyzetbe. Folytassa és próbálja meg eltávolítani ezt a kódot, hogy megnézze, mi történik.

Az oldal frissítésekor láthatja, hogy a körök addig igazodnak, amíg végül stabilizálódnak. A jelöléssel ellátott () funkció frissíti a körök helyzetét. A d3.forceManyBody () folyamatosan frissíti az egyes csomópontok x és y helyzetét, és a bejelölt () függvény frissíti a DOM-ot ezekkel az értékekkel (cx és cy attribútumok).

// bubble_graph.js
funkció bejelölve (e) {
    node.attr ("cx", (d) függvény {return d.x;})
        .attr ("cy", (d) függvény {vissza d.y;});
    // A „csomópont” a buborékdiagram mindegyik köre
 }

Itt van a kód mindent együtt:

var szimuláció = d3.forceSimulation (adatok)
    .force ("töltés", d3.forceManyBody (). erő ([- 50]))
    .force ("x", d3.forceX ())
    .force ("y", d3.forceY ())
    .on ("kullancs", pipálva);
funkció bejelölve (e) {
    node.attr ("cx", (d) függvény {return d.x;})
        .attr ("cy", (d) függvény {vissza d.y;});
}

Összefoglalva: ez a szimuláció az, hogy minden körnek x és y helyzetet ad.

3. d3.scales

Itt jön a legizgalmasabb rész: a körök hozzáadása. Emlékszel az enter () függvényre? Most már fogja használni. Diagramunkban az egyes körök sugara arányos az egyes történetek ajánlásainak számával. Ehhez egy lineáris skálát kell használni: d3.scaleLinear ()

A skálák használatához két dolgot kell meghatároznia:

  • Tartomány: a bemeneti adatok minimális és maximális értéke (esetünkben az ajánlások minimális és maximális száma). A minimális és a maximális érték eléréséhez a d3.min () és d3.max () függvényeket kell használni.
  • Tartomány: a skála minimális és maximális kimeneti értéke. Esetünkben az 5-ös méret legkisebb sugara és a 18-as legnagyobb sugara akarjuk.
// bubble_graph.js
var scaleRadius = d3.scaleLinear ()
            .domain ([d3.min (adatok, (d) funkció) {visszatérés + d.megtekintések;}),
                    d3.max (adatok, (d) függvény {visszatérés + d.megtekintések;})])
            .range ([5,18]);

És akkor végre létrehozza a köröket:

// bubble_graph.js
var node = svg.selectAll ("kör")
   .data (adatok)
   .belép()
   .append ( "kör")
   .attr ('r', funkció (d) {return scaleRadius (d.views)})
});

A körök színezéséhez kategorikus skálát használ: d3.scaleOrdinal (). Ez a skála diszkrét értékeket ad vissza.

Adatkészletünk 3 kategóriába tartozik: tervezés, fejlesztés és adattudomány. E kategóriák mindegyikét színnel leképezi. A d3.schemeCategory10 10 színt tartalmaz, amely elegendő számunkra.

// bubble_graph.js
var colorCircles = d3.scaleOrdinal (d3.schemeCategory10);

var node = svg.selectAll ("kör")
    .data (adatok)
    .belép()
    .append ( "kör")
    .attr ('r', funkció (d) {return scaleRadius (d.views)})
    .style ("kitöltés", (d) függvény {return colorCircles (d.kategória)});

Azt akarod, hogy a körök az SVG közepére legyenek rajzolva, így minden kört a közepére kell mozgatni (a szélesség fele és a magasság fele). Haladjon tovább, és távolítsa el ezt a kódból, hogy megnézze, mi történik.

// bubble_graph.js
var node = svg.selectAll ("kör")
 .data (adatok)
 .belép()
 .append ( "kör")
 .attr ('r', funkció (d) {return scaleRadius (d.views)})
 .style ("kitöltés", (d) függvény {return colorCircles (d.kategória)}))
 .attr ('transzformáció', 'fordítás (' + [szélesség / 2, magasság / 2] + ')');

Most hozzáteszi a tippeket a diagramhoz. Meg kell jelenniük, amikor az egeret a körökre helyezzük.

var tooltip = kiválasztás
 .append ( "div")
 .style ("pozíció", "abszolút")
 .style ("láthatóság", "rejtett")
 .style ("színes", "fehér")
 .style ("padding", "8px")
 .style ("háttér szín", "# 626D71")
 .style ("határ-sugár", "6 képpont")
 .style ("text-align", "center")
 .style ("font-család", "monospace")
 .style ("szélesség", "400 képpont")
 .szöveg("");
var node = svg.selectAll ("kör")
 .data (adatok)
 .belép()
 .append ( "kör")
 .attr ('r', funkció (d) {return scaleRadius (d.views)})
 .style ("kitöltés", (d) függvény {return colorCircles (d.kategória)}))
 .attr ('átalakítás', 'fordítás (' + [szélesség / 2, magasság / 2] + ')')
 .on ("egérmutató", (d) függvény {
     tooltip.html (d.kategória + "
" + d.title + "
" + d.megtekintések);      return tooltip.style ("láthatóság", "látható");})  .on ("mousemove", function () {    return tooltip.style ("felső", (d3.event.pageY-10) + "px"). stílus ("bal", (d3.event.pageX + 10) + "px";})  .on ("mouseout", function () {return tooltip.style ("láthatóság", "rejtett");});

Az egér mozgatásakor a kurzort követi. d3.event.pageX és d3.event.pageY adja vissza az egér koordinátáit.

És ez az! A végleges kódot itt láthatja.

Itt játszhatsz a buborékdiagrammal.

Hasznosnak találta ezt a cikket? Minden tőlem telhetőt megteszek, hogy minden hónapban mélyebb merülési cikkeket írjak. E-mailt kaphat, amikor újat teszek közzé.

Van kérdése vagy javaslata? Hagyja őket a megjegyzésekben. Köszönöm, hogy elolvasta!

Külön köszönet John Carmichaelnek és Alexandre Cisneirosnak.