Tutorial de D3.js: Creación de gráficos de barras interactivos con JavaScript

Para el tutorial de hoy vamos a empezar a diseñar y crear gráficos de barras usando D3.js, sigue leyendo para que sepas cómo hacerlo

Primero que todo ¿Qué es D3.js?

D3.js es una biblioteca de JavaScript basada en datos para manipular elementos DOM.

“D3 te ayuda a dar vida a los datos mediante HTML, SVG y CSS. El énfasis de D3 en los estándares web le brinda todas las capacidades de los navegadores modernos sin atarse a un marco propietario, combinando poderosos componentes de visualización y un enfoque basado en datos para la manipulación de DOM «. – d3js.org

¿Por qué deberías crear gráficos con D3.js? ¿Por qué no solo mostrar una imagen?

Bueno, los gráficos se basan en información proveniente de recursos de terceros que requieren una visualización dinámica durante el tiempo de procesamiento. Además, SVG es una herramienta muy poderosa que se adapta bien a este caso de aplicación.

Tomemos un desvío para ver qué beneficios podemos obtener del uso de SVG.

Los beneficios de SVG

SVG significa gráficos vectoriales escalables, que técnicamente es un lenguaje de marcado basado en XML.

Se usa comúnmente para dibujar gráficos vectoriales, especificar líneas y formas o modificar imágenes existentes.

Pros:

  • Compatible con todos los principales navegadores
  • Tiene interfaz DOM, no requiere lib de terceros
  • Escalable, puede mantener alta resolución
  • Tamaño reducido en comparación con otros formatos de imagen.

Contras:

  • Solo puede mostrar imágenes bidimensionales;
  • Larga curva de aprendizaje
  • Render puede tomar mucho tiempo con operaciones intensivas de cómputo.
  • A pesar de sus inconvenientes, SVG es una gran herramienta para mostrar iconos, logotipos, ilustraciones o, en este caso, gráficos.

Empezando con D3.js

Elegí el gráfico de barras para comenzar porque representa un elemento visual de baja complejidad mientras enseña la aplicación básica de D3.js en sí. Esto no debería engañarte, D3 proporciona un gran conjunto de herramientas para visualizar datos.

Un gráfico de barras puede ser horizontal o vertical en función de su orientación. Iré con el gráfico de columnas alias vertical.

En este diagrama, voy a mostrar los 10 lenguajes de programación más populares según el resultado de la Encuesta de Desarrolladores 2018 de Stack Overflow .

¡Hora de dibujar!

SVG tiene un sistema de coordenadas que comienza desde la esquina superior izquierda (0; 0). El eje x positivo va hacia la derecha, mientras que el eje y positivo va hacia la parte inferior. Por lo tanto, la altura de la SVG debe tenerse en cuenta a la hora de calcular la coordenada y de un elemento.

Quiero crear un gráfico con 1000 píxeles de ancho y 600 píxeles de altura.


<body>
<svg />
</body>
<script>
const margin = 60;
const width = 1000 - 2 * margin;
const height = 600 - 2 * margin;

const svg = d3.select('svg');
</script>


En el fragmento de código anterior, selecciono el elemento <svg> creado en el archivo HTML con D3 select. Este método de selección acepta todo tipo de cadenas de selección y devuelve el primer elemento coincidente. Utiliza selectAll si desea obtener todos ellos.

También defino un valor de margen que le da un poco de relleno adicional al gráfico. El relleno se puede aplicar con un elemento <g> traducido por el valor deseado. De ahora en adelante, recurro a este grupo para mantener una buena distancia de cualquier otro contenido de la página.


const chart = svg.append('g')
.attr('transform', `translate(${margin}, ${margin})`);


Agregar atributos a un elemento es tan fácil como llamar al método attr. El primer parámetro del método toma un atributo que quiero aplicar al elemento DOM seleccionado. El segundo parámetro es el valor o una función de devolución de llamada que devuelve su valor. El código anterior simplemente mueve el inicio del gráfico a la posición (60; 60) del SVG.

Formatos de entrada D3.js soportados

Para comenzar a dibujar, necesito definir la fuente de datos de la que estoy trabajando. Para este tutorial, uso una matriz de JavaScript simple que contiene objetos con el nombre de los idiomas y sus porcentajes, pero es importante mencionar que D3.js admite varios formatos de datos.

La biblioteca tiene una funcionalidad incorporada para cargar desde XMLHttpRequest, archivos .csv, archivos de texto, etc. Cada una de estas fuentes puede contener datos que D3.js puede usar, lo único importante es construir una matriz a partir de ellos. Ten en cuenta que, a partir de la versión 5.0, la biblioteca utiliza promesas en lugar de devoluciones de llamada para cargar datos, lo que no es un cambio compatible con versiones anteriores.

Escalado y ejes

Continuemos con los ejes del gráfico. Para dibujar el eje y, necesito establecer el límite de valor más bajo y más alto, que en este caso son 0 y 100.

Estoy trabajando con porcentajes en este tutorial, pero hay funciones de utilidad para tipos de datos distintos de los números que explicaré más adelante.

Tengo que dividir la altura del gráfico entre estos dos valores en partes iguales. Para esto, creo algo que se llama una función de escalado.


const yScale = d3.scaleLinear()
.range([height, 0])
.domain([0, 100]);


La escala lineal es el tipo de escala más conocido. Convierte un dominio de entrada continuo en un rango de salida continuo. Observa el método rangey domain. El primero toma la longitud que debe dividirse entre los límites de los valores del dominio.

Recuerda, el sistema de coordenadas SVG comienza desde la esquina superior izquierda, por eso el rango toma la altura como primer parámetro y no a cero.

Crear un eje a la izquierda es tan simple como agregar otro grupo y llamar al método axisLeft de D3 con la función de escala como parámetro.


chart.append('g')
.call(d3.axisLeft(yScale));


Ahora, continúa con el eje x.


const xScale = d3.scaleBand()
.range([0, width])
.domain(sample.map((s) => s.language))
.padding(0.2)

chart.append('g')
.attr('transform', `translate(0, ${height})`)
.call(d3.axisBottom(xScale));
d3-js-tutorial-bar-chart-labels

Ten en cuenta que utilizo scaleBand para el eje x, que ayuda a dividir el rango en bandas y calcular las coordenadas y los anchos de las barras con relleno adicional.

D3.js también es capaz de manejar el tipo de fecha entre muchos otros. scaleTime es realmente similar a scaleLinear, excepto que el dominio es aquí un conjunto de fechas.

Barras de dibujo en D3.js

Piensa en qué tipo de entrada necesitamos para dibujar las barras. Cada uno representa un valor que se ilustra con formas simples, específicamente rectángulos. En el siguiente fragmento de código, los adjunto al elemento de grupo creado.


chart.selectAll()
.data(goals)
.enter()
.append('rect')
.attr('x', (s) => xScale(s.language))
.attr('y', (s) => yScale(s.value))
.attr('height', (s) => height - yScale(s.value))
.attr('width', xScale.bandwidth())

Primero, usa selectAll para seleccionar los elementos en el gráfico que regresa con un conjunto de resultados vacío. Luego, la función data que indica cuántos elementos debe actualizarse el DOM según la longitud del arreglo. enter identifica los elementos que faltan si la entrada de datos es más larga que la selección. Esto devuelve una nueva selección que representa los elementos que deben agregarse. Por lo general, esto es seguido por un elemento append que agrega elementos al DOM.

Básicamente, le digo a D3.js que agregue un rectángulo para cada miembro de la matriz.

Ahora, esto solo agrega rectángulos uno encima del otro que no tienen altura ni ancho. Estos dos atributos tienen que calcularse y ahí es donde las funciones de escalado vuelven a ser útiles.

Mira, agrego las coordenadas de los rectángulos con la attrllamada. El segundo parámetro puede ser una devolución de llamada que toma 3 parámetros: el miembro real de los datos de entrada, su índice y toda la entrada.


.attr(’x’, (actual, index, array) =>
xScale(actual.value))


La función de escala devuelve la coordenada para un valor de dominio dado. El cálculo de las coordenadas es un pedazo de pastel, el truco está con la altura de la barra. La coordenada y calculada se debe restar de la altura del gráfico para obtener la representación correcta del valor como una columna.

Yo defino el ancho de los rectángulos con la función de escalado también scaleBand tiene una función bandwidth que devuelve el ancho calculado para un elemento en función del conjunto de relleno.


d3-js-tutorial-bar-chart-drawn-out-with-javascript

Buen trabajo, pero no tan elegante, ¿verdad?

Para evitar que nuestra audiencia se aburra, ¡agreguemos información y mejoremos las imágenes para que tu gráfico se vea mucho mejor!