Todos los datos cuentan una historia, el reto es interpretarlos y mostrarlos correctamente para contar esta historia lo mejor posible. Si tus datos se mueven a lo largo del tiempo, ¿por qué no mostrarlos, justamente, moviéndose? Las gráficas animadas son una excelente forma de contar esta historia. Hoy, vamos a ver cómo integrar un tipo de gráfica avanzada llamada ‘Bar Chart Race’ o ‘Carrera de gráfica de barras’, en la que podremos ver el comportamiento de la información a lo largo del tiempo de una forma muy impresionante.

Preparando nuestros datos

Lo primero que haremos, como siempre, es preparar nuestros datos y pensar un poco sobre lo que queremos lograr. Tenemos este set de datos con información del valor de mercado de varias empresas a lo largo de los años. Cada dato se compone del nombre de una empresa asociada a una fecha, a una categoría y a un valor en dólares por cada año desde el 2000 hasta el 2019. De la fecha completa solo usaremos el año, pero en tus datos podrías animar la progresión por mes o por día como te convenga si los agrupas así de antemano. La categoría se usará para mostrar un color diferente para las barras para contrastar y comparar las industrias.

Es importante notar que para que funcione todo lo que haremos después, si queremos cambiar de set de datos, los datos deben tener esta estructura de Fecha – Nombre – Categoría – Valor. Si tus datos están acomodados de otra forma, primero deberás trabajar en adaptarlos.

Crear componentes HTML en una hoja de cálculo

Nuestro objetivo entonces será lograr una gráfica animada de tipo Bar Chart Race, y para eso utilizaremos la librería de graficación D3.js para que esta haga su magia con nuestros datos dentro de nuestra misma hoja de Cálculo de Google Sheets. Existe ya un ejemplo construido y cuyo código es abierto que podemos usar. En este repositorio encontraremos también los datos de prueba que estaremos usando en esta guía.

Para poder utilizar la librería que necesitamos, tenemos que crear un componente HTML dentro de nuestra hoja de cálculo, es decir, crear una pequeña página web que nos permita importar código de JavaScript para crear nuestras propias funcionalidades. Para esto tendremos que usar código de Apps Script, pero no te preocupes, de aquí puedes copiar y pegar lo que vayas necesitando.

El reto estará en leer los datos de la hoja de cálculo, crear este componente HTML desde un menú, darle los datos a la librería en el formato y estructura que los pide y finalmente mostrar la gráfica animada.

Preparar el proyecto de Apps Script

Entonces, para comenzar abrimos el menú Extensiones – Apps Script y reemplazamos el código que aparece por default por este otro, donde estamos creando un menú que llama a la función que generará la gráfica

function onOpen() {
 SpreadsheetApp.getUi()
  .createMenu("Gráficas")
    .addItem("Generar gráfica", "grafica_html")
    .addToUi();
}
Lenguaje del código: JavaScript (javascript)

Leer los datos de la hoja de cálculo hacia Apps Script

Ahora vamos a crear una función que leerá los datos de la hoja de cálculo y los regresará como un objeto que todo el código posterior podrá manipular. Aquí es importante notar que deberás adaptar esta parte del código si quieres tomar en cuenta otras columnas o en un orden diferente al del set de datos que estamos revisando, porque el mapeo es uno a uno a partir del orden en el que están, y el código que sigue espera estos nombres de variables exactos: date, name, category y value.

function leer_datos() {
  var ultima_fila = SpreadsheetApp.getActiveSheet().getLastRow();
  var ultima_columna = SpreadsheetApp.getActiveSheet().getLastColumn();
  var dataRange = SpreadsheetApp.getActiveSheet().getRange(fila_inicial=2, columna_inicial=1,ultima_fila, ultima_columna);
  var data_values = dataRange.getValues();

  // se mapea cada elemento del arreglo a una propiedad en el orden que vienen las columnas y se filtran valores de name vacíos
  return data_values.map(([date, name, category, value]) => (
    { date, name, category, value }))
    .filter(d => (d.name == "" ? false : true));
}
Lenguaje del código: JavaScript (javascript)

Después, agregamos la función a la que estamos llamando en el menú, que es grafica_html . En ella estamos creando una plantilla de HTML a partir de un archivo, que crearemos en un momento. Además, vamos a adjuntarle nuestros datos a este objeto en una propiedad que usaremos después, utilizando la función que acabamos de crear hace un momento para leer los datos. Esto funciona porque Apps Script hará un procesamiento previo del html con el método evaluate para poder mostrarlo después. Es parecido a la manera en que funciona un servidor de PHP o de node, o en otras palabras, un backend.

function grafica_html() {
  var html = HtmlService.createTemplateFromFile('grafica');
  html.datos = leer_datos();
  SpreadsheetApp.getUi().showModalDialog(html.evaluate().setHeight(800).setWidth(1000),"Gráfica");
}
Lenguaje del código: JavaScript (javascript)

El archivo final se verá algo así:

Código.gs

function onOpen() {
 SpreadsheetApp.getUi()
  .createMenu("Gráficas")
    .addItem("Generar gráfica", "grafica_html")
    .addToUi();
}

function leer_datos() {
  var ultima_fila = SpreadsheetApp.getActiveSheet().getLastRow();
  var ultima_columna = SpreadsheetApp.getActiveSheet().getLastColumn();
  var dataRange = SpreadsheetApp.getActiveSheet().getRange(fila_inicial=2, columna_inicial=1,ultima_fila, ultima_columna);
  var data_values = dataRange.getValues();

  // se mapea cada elemento del arreglo a una propiedad en el orden que vienen las columnas y se filtran valores de name vacíos
  return data_values.map(([date, name, category, value]) => (
    { date, name, category, value }))
    .filter(d => (d.name == "" ? false : true));
}

function grafica_html() {
  var html = HtmlService.createTemplateFromFile('grafica');
  html.datos = leer_datos();
  SpreadsheetApp.getUi().showModalDialog(html.evaluate().setHeight(800).setWidth(1000),"Gráfica");
}
Lenguaje del código: JavaScript (javascript)

Creando el HTML de la gráfica

Lo que sigue ahora es crear dos archivos necesarios para mostrar la gráfica animada de Bar Chart Race.

Creamos el primer archivo dando click en el signo de + , elegimos la opción HTML y le ponemos por nombre grafica. Esto creará un archivo con el nombre completo de grafica.html, automáticamente completando la extensión. Esto es porque en proyectos de Apps Script por seguridad solo se nos permite integrar archivos adicionales de tipo html.

El código por default que vemos lo reemplazaremos por el siguiente, que trae todo lo necesario para mostrar nuestra gráfica.

grafica.html

<!DOCTYPE html>
<html>
  <head>
    <style>
      html, body {
        overflow: hidden;
        font-family: Arial, Helvetica, sans-serif;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #bar-chart-race > text:last-child {
          font-size: 4em !important;
          font-weight: bold !important;
      }
      #bar-chart-race g ~ g ~ g text {
        font-weight: bold !important;
      }
    </style>
    <base target="_top">
  </head>
  <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js"></script>
    <?!= HtmlService.createHtmlOutputFromFile('chartjs').getContent(); ?>
    <script>
      const data_sheet = <?!= JSON.stringify(datos) ?>;
      const data = data_sheet.map(x => {
        x.date = new Date(x.date);
        return x;
      });
      const play = () => {
        const chart = barChartRace(data, {
          svgId: 'bar-chart-race'
          });
          d3.select('#bar-chart-race').remove();
          d3.select('body').append(() => chart);
          chart.play();
      }

      const button = d3.select('body').append('div').append('button')
        .attr('type', 'button').attr('class','reiniciar').text('Reiniciar');

      // iniciar animación al cargar la página
      play();

      // reiniciar al dar click en el botón
      button.on('click', () => {
        play();
      });
    
    </script>
  </body>
</html>

Lenguaje del código: HTML, XML (xml)

Vamos a explicar un poco de qué hacen algunas de las cosas aquí. Como puedes ver, además de un poco de estilo CSS, estamos importando la librería D3. Después, usando un formato especial de Apps Script, ejecutamos el servicio de HTML incluido para traer el archivo que crearemos en unos momentos, que controlará esta librería.

<?!= HtmlService.createHtmlOutputFromFile('chartjs').getContent(); ?>
Lenguaje del código: HTML, XML (xml)

Luego, estamos usando el mismo método para traer la variable datos que hicimos en el archivo de Apps Script anterior. Es necesario procesarla de esta manera con JSON.stringify para que pueda, de cierto modo, vivir en nuestro HTML y no nos preocupemos por el momento por maneras más complicadas de obtener la información.

const data_sheet = <?!= JSON.stringify(datos) ?>;
Lenguaje del código: PHP (php)

Aquí hay un detalle que debemos tomar en cuenta, y es que al convertir todo el objeto a string, perdemos el objeto Date, que D3 necesita forzosamente. Es por eso que volvemos a procesar solamente esta propiedad y la regresamos a que sea un objeto Date, teniendo nuestro objeto de data listo para que D3 lo trabaje.

Incluir controlador de la gráfica Bar Chart Race

Finalmente vamos a crear el segundo archivo HTML necesario, que es donde vivirá el código que tomaremos del ejemplo de Bar Chart Race de Takanori Fujiwara. Usamos de nuevo el menú del signo de +, elegimos HTML y ahora lo nombramos chartjs, de nuevo, sin escribir .html, porque eso se agregará automáticamente.

Aquí borramos el contenido, creamos una etiqueta <script></script> y dentro pegamos precisamente el contenido del archivo chart.js del repositorio de Takanori.

Antes de guardar este archivo tenemos que hacerle una modificación muy pequeña para que funcione en Apps Script. Solamente le borramos la palabra export en la línea 27, y guardamos. Esto es porque Apps Script no soporta los módulos de la especificación ES6 de JavaScript y nos dará error si lo dejamos. Y antes de irte de este archivo, puedes jugar con algunas de las variables disponibles ahí mismo para configurar la gráfica. Yo por ejemplo, cambié el número de barras que aparecen en pantalla, modificando la variable n a 11 porque si no, no cabían. Y lo mismo con el valor de la variable width, osea el ancho, que rebajé a 1000.

Gráfica animada “Bar Chart Race” en una hoja de cálculo de Google Sheets

Ya estamos a punto de terminar y ver el resultado final, ¡qué emoción! después de tanto copiar y pegar, uno se sí se cansa eh 😉

Regresamos a nuestra hoja de cálculo, y si todavía no vemos el menú personalizado, simplemente refrescamos la página y debería aparecer. Lo usamos una vez para que nos pregunte por los permisos de ejecución que requiere Apps Script, los permitimos, y volvemos a usar nuestro menú para ahora sí ver el resultado.

Usar cualquier set de datos para generar la gráfica Bar Chart Race

D3.js es muy flexible y permite hacer prácticamente lo que sea, pero también hay que decir que no es tan amigable como nos gustaría, pues hay que construir todo lo que se requiere hacer prácticamente a mano. Es por eso que para esta demostración estamos usando un ejemplo que ya estaba disponible para nosotros, pero al mismo tiempo, nada nos detiene de modificar este ejemplo para adaptarlo a nuestro gusto y con nuestros datos.

Probemos con otro set de datos entonces. Ahora usaré un set de datos público sobre los casos de COVID-19 por país y por mes desde 2020 hasta 2022, que obtuve del repositorio Our World In Data.

El resultado a veces puede ser hipnotizante, por eso esta forma de visualizar datos es tan popular. ¿Está genial no? 😉

Si quieres adentrarte aun más en este tema, hay muchas más tipos de gráfica que puedes implementar con este método.

Plantilla terminada para descargar

Guía en video

Si tienes dudas puedes ver esta misma guía explicada en video

¡Espero que te haya sido útil esta guía! No olvides seguirnos en YouTube para más tips, trucos y guías de productividad.

Si te interesa aprender más sobre Google Sheets, checa nuestro Curso: Aprende Sheets en el que Alekz te guiará para elevar tu aprendizaje de hojas de cálculo al nivel experto.

Aprende Sheets: Curso práctico de Hojas de cálculo de Google
Aprende Sheets: Curso práctico de Hojas de cálculo de Google