Vytvářejte skvělé grafy a vizualizujte data pomocí d3.js

Pravděpodobně jste již nějakou dobu viděli mnoho aplikací „covidtracker“ nebo kryptoměnových grafů, některé z nich nabízejí opravdu úžasné grafy, které jen stěží vytvoříte pomocí běžných knihoven „ready to make“ grafů.

Musím přiznat... miluji hraní si s daty a když vidím tyhle druhy krásných uživatelských rozhraní se všemi těmi čísly tak dobře prezentovanými, žárlím, říkal jsem si:oh, opravdu to potřebuji umět postavit!
Nedávno jsem tedy začal strkat hlavu do slavné knihovny d3.js.
Nečekejte, že zde přijdu s něčím působivým, ne, ale doufám, že to bude dobrý základ, který vám představí vizualizaci dat pomocí d3.js.

Co se chystáme vytvořit, je sloupcový graf 10 nejlepších obyvatel podle země:

DEMO

Co je d3.js?


Ve skutečnosti d3.js není knihovna grafů, je to druh velkého API pro manipulaci s DOM a nabízí mnoho funkcí utilit. Můžete manipulovat se svg, canvas, html a tak vytvářet tabulky, grafy, mapy, vše, co chcete pro vizualizaci dat.
Největší výhodou použití d3 je, že každá skvělá vizualizace dat, kterou jste kdy viděli na webu, je pravděpodobně proveditelná pomocí d3.js.
Hlavní nevýhodou je, že d3.js může být zpočátku ohromující a podle mého názoru je docela těžké se ho naučit.

Sestavte aplikaci

Připravte projekt:


Nepoužijeme zde žádný framework ani konkrétní konfiguraci jen pro jednoduchost nějaký čistý javascript.

Vytvořte soubor index.html a zahrňte toto:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>d3.js Demo</title>
</head>
<body>
    <h1>Top 10 population by country</h1>
    <div id="chart"></div>
    <div id="tooltip">
        <h3 id="country_name"></h3>
        <p id="country_population"></p>
    </div>

    <script src="https://d3js.org/d3.v6.js"></script>
    <script src="index.js"></script>
</body>
</html>

Importujeme knihovnu d3.js a soubor index.js, který bude obsahovat náš kód.

Vytvořte soubor style.css s těmito styly:

* {
    margin: 0;
    box-sizing: border-box;
}

body {
    box-sizing: border-box;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    font-family: Avenir, Helvetica, Arial, sans-serif;
}

svg {
    background-color: #2a2a2e;
    color: white;
    border-radius: 5px;
}

h1 {
    padding-bottom: 2rem;
}

#tooltip {
    position: absolute;
    visibility: hidden;
    background-color: white;
    font-size: .7rem;
    border-radius: 5px;
    padding: .3rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
    text-align: center;
}

#country_name {
    padding: .3rem;
}

#country_population {
    padding: .3rem;
}

.bar {
    transition: .2s all;
}

Nakonec přidejte soubor index.js. Nyní jsme připraveni začít kódovat.

Připravte data


Budeme používat restcountries API.

V grafu chceme zobrazit seznam 10 nejlepších zemí z hlediska počtu obyvatel, takže potřebujeme pouze název a populaci pro osu x/y každé země.

Začněme shromažďováním těchto dat a jejich formátováním do požadovaného tvaru:

const API_URL = 'https://restcountries.eu/rest/v2/all';

const getData = async () => {
  const reponse = await fetch(API_URL);
  const result = await reponse.json();
  // Sort by population
  const dataSort = result.sort((a, b) => b.population - a.population);
  // only keep the top 10 population
  dataSort.length = 10;
  // We only need name + population
  const dataReady = dataSort.map((country) => ({
    name: country.name,
    population: Math.floor(country.population / 1000000),
  }));
  return dataReady;
};

Nyní máme přesně to, co potřebujeme:

https://i.gyazo.com/384c61698aae5dc6f39c86d8b5447150.png

Sestavte graf:

Vytvořte hlavní prvek

Vytvořte novou funkci, která bude mít na starosti generování sloupcového grafu pomocí d3:

const generateChart = (popData) => {
  const margin = {
    top: 20,
    right: 40,
    bottom: 60,
    left: 80,
  };
  const width = 1000 - margin.left - margin.right;
  const height = 500 - margin.top - margin.bottom;

  // Create svg
  const svgElement = d3
    .select('#chart')
    .append('svg')
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + margin.top + margin.bottom)
    .append('g')
    .attr('transform', `translate(${margin.left},${margin.top})`);
}

Všimněte si, jak používáme "d3.select" k výběru prvku dom a řetězí další metody, jako je "append" a "attr", ke konstrukci našich prvků. To jsou opravdu základy d3.
Proměnné margin, width a height slouží k nastavení pozice našeho prvku svg a budou použity také k umístění naší osy.

Vytvořit osu

Dále vytvoříme naši osu pomocí metod měřítka d3:

    // Add X axis
    const xScale = d3.scaleBand()
    .range([0, width])
    .domain(popData.map((s) => s.name))
    .padding(0.2)
    svgElement.append('g')
        .attr('transform', `translate(0, ${height})`)
        .call(d3.axisBottom(xScale));

    // Add Y axis
    const yScale = d3.scaleLinear()
        .domain([popData[0].population, popData[9].population])
        .range([0, height]);
    svgElement.append('g')
        .call(d3.axisLeft(yScale));

   // Add grid
   svgElement
    .append('g')
.call(d3.axisLeft(yScale).ticks().tickSize(-width).tickFormat(''));

Použili jsme několik obslužných metod z části d3 modulu scale ke správnému zmapování naší osy s daty (scaleLinear, scaleBand).
Pokud otevřete navigátor, uvidíte nyní prvek svg se dvěma osami, ale zatím bez dat.

Znázorněte data pomocí pruhů

Abychom svá data reprezentovali pruhem, jednoduše vytvoříme obdélníky a přidáme je do našeho hlavního prvku svg se správnou šířkou a poměrem opět díky určitým metodám d3-scale (šířka pásma, xScale, yScale):

  // Draw the bars
  svgElement
    .append('g')
    .selectAll('.bar')
    .data(popData)
    .enter()
    .append('rect')
    .attr('class', 'bar')
    .attr('x', (d) => xScale(d.name))
    .attr('width', xScale.bandwidth())
    .attr('y', (d) => yScale(d.population))
    .attr('height', 0)
    .style('fill', '#00FA9A')
    .transition()
    .duration(750)
    .attr('height', (d) => height - yScale(d.population));

Náš graf právě funguje, ale pojďme to udělat trochu „živější“.

Přidat popisek a efekt umístění kurzoru:

Chceme ukázat přesnou populaci, když najedeme na jeden pruh, takže musíme vytvořit nápovědu a přidat události myši na každý pruh.
Pamatujte:na naší stránce index.html je prvek div s ID popisku a některé styly v css. Ve skutečnosti bylo vše připraveno, nápověda je tam, ale je skrytá, prostě teď musíme přidat událost myši:

 // create a tooltip
  const tooltip = d3.select('#tooltip');
  const tooltip_name = d3.select('#country_name');
  const tooltip_pop = d3.select('#country_population');

  // Add mouse event to show the tooltip when hovering bars
  d3.selectAll('.bar')
    .on('mouseover', function () {
      d3.select(this).style('fill', '#59ffb2');
      tooltip.style('visibility', 'visible');
    })
    .on('mousemove', function (e, d) {
      tooltip
        .style('top', event.pageY - 10 + 'px')
        .style('left', event.pageX + 10 + 'px');
      tooltip_name.text(d.name);
      tooltip_pop.text(`Population: ${d.population} Millions`);
    })
    .on('mouseout', function () {
      d3.select(this).style('fill', '#00FA9A');
      tooltip.style('visibility', 'hidden');
    });

Přidat textový popisek pro osu :

  // text label for the y axis
  svgElement
    .append('text')
    .attr('transform', 'rotate(-90)')
    .attr('y', 0 - margin.left)
    .attr('x', 0 - height / 2)
    .attr('dy', '1em')
    .style('text-anchor', 'middle')
    .style('fill', 'white')
    .text('Population (in millions)');

  // text label for the y axis
  svgElement
    .append('text')
    .attr('y', height + 30)
    .attr('x', 0 + width / 2)
    .attr('dy', '1em')
    .style('text-anchor', 'middle')
    .style('fill', 'white')
    .text('Country name');  

Spusťte kód:

V hlavním rozsahu jednoduše provádějte naše funkce

getData().then(generateChart);

A tady to je, teď byste měli mít tento výsledek.

Pokud chcete zkontrolovat celý kód:zde

V doméně vizualizace dat je opravdu tolik možností a věcí, které lze postavit, buďte zvědaví a prozkoumejte!
Doufám, že jsem se vyjádřil dostatečně jasně a že vám to pomohlo pochopit konstrukci grafu pro vytvoření lepšího uživatelského rozhraní.

Přeji hezký den!