Los errores que ya no deberías cometer
El catálogo de los fallos del track agrupados por familia, con el síntoma que producen, la causa real y el sitio donde se resolvió cada uno.
Un catálogo de errores es más útil que un catálogo de buenas prácticas, porque los errores se reconocen por su síntoma y las buenas prácticas hay que recordarlas. Estos son los que aparecen una y otra vez en gráficos escritos por gente competente, agrupados por familia, con lo que se ve, lo que pasa por debajo y dónde está la respuesta.
- Reconocer un fallo de geometría por su síntoma visual.
- Identificar los errores estructurales de un SVG generado por código.
- Detectar los fallos de representación que no producen ningún error técnico.
- Auditar un gráfico propio con la lista completa.
Geometría, nitidez y coordenadas
El gráfico se ve borroso. El búfer del lienzo tiene el tamaño CSS en lugar del tamaño en píxeles de dispositivo. Se corrige multiplicando por el ratio y compensando con una transformación, y hay que rehacerlo cuando el ratio cambia, no solo al montar.
Una línea de un píxel se ve gris y de dos píxeles de grosor. Cae entre dos filas de píxeles. En lienzo, desplaza medio píxel; en SVG, shape-rendering="crispEdges". Y si las dos capas tienen que alinearse, usa el mismo criterio en las dos, según el enfoque híbrido.
El tooltip aparece desplazado, y más cuanto más a la derecha. El sistema de coordenadas del evento y el del dibujo no coinciden. Las tres causas: no restar la caja del elemento, no dividir por el ratio de píxeles al leer del lienzo de aciertos, y redondear el tamaño del búfer sin ajustar el viewBox de la capa de encima.
El gráfico entero es NaN y no se dibuja nada. Un dominio degenerado: todos los valores iguales, o un array vacío. La escala divide por cero. Se trata devolviendo el punto medio del rango, y hay que hacerlo en la escala, no en cada punto de uso.
Al reducir el contenedor, todo se descoloca. Coordenadas negativas porque el ancho menos los márgenes ha dado un número menor que cero. Un Math.max(0, ...) en el cálculo de dimensiones lo evita.
El panel se arrastra al redimensionar. El redibujado no se difiere a un fotograma, o se está leyendo el tamaño con getBoundingClientRect dentro del propio observador. Los dos se resuelven en el patrón de componente de gráfico.
SVG generado por código
Los elementos no aparecen aunque estén en el DOM. createElement en lugar de createElementNS. El elemento existe, tiene el nombre correcto y pertenece al namespace de HTML, así que no es un elemento SVG. El inspector no lo distingue a simple vista, y por eso este fallo se busca durante horas. Está en createElementNS y el namespace.
El gradiente no se ve, o se ve como un color plano. Casi siempre es una caja envolvente con una dimensión nula, típicamente una línea horizontal o vertical, con el gradiente declarado en unidades de caja. La explicación completa está en gradientUnits.
Al meter dos iconos en la misma página, uno pierde su gradiente. Colisión de identificadores: los id de un SVG en línea son globales del documento. Está en las referencias por id y el ámbito global.
La sombra o el desenfoque salen cortados. La región del filtro tiene un tamaño por defecto que no cubre lo que el efecto expande. Se amplía con x, y, width y height en el filter.
El SVG exportado no usa la fuente correcta. Un SVG cargado como imagen no puede traer recursos externos, incluidas las fuentes. Está en las fuentes en un SVG exportado.
El fichero descargado no abre en otras aplicaciones. Falta el xmlns en la raíz. Dentro del HTML no hace falta; fuera, sí.
Optimizar el SVG rompió los estilos. Un plugin de optimización ha convertido formas en path, o ha quitado atributos que un selector usaba, o ha renombrado identificadores. Está en SVGO y los plugins que rompen.
El gráfico se reconstruye entero en cada actualización. innerHTML vacío y volver a crear. Se pierden foco, transiciones e identidad de los elementos. La alternativa está en actualizar en vez de recrear.
Representación: los fallos que no dan ningún error
Estos son los peores, porque el código funciona perfectamente.
Las barras no empiezan en cero. La barra codifica con longitud y una longitud sin origen no significa nada. En un gráfico de líneas, en cambio, no truncar puede ser el error.
Los círculos escalan con el radio. El área crece con el cuadrado, así que la diferencia se exagera cuadráticamente. La corrección es la raíz cuadrada.
Un icono el doble de grande para el doble de valor. El mismo error, con imágenes, y por tanto sin ninguna línea de código sospechosa.
El eje dual. El punto de cruce y la correlación aparente los eliges tú al elegir los dos rangos. Las tres alternativas están en los errores clásicos.
La paleta divergente centrada en la mitad de los datos. El neutro cae en un valor arbitrario y el gráfico afirma que crecer un poco es malo. Se comprueba mirando de qué color sale el cero.
Una paleta cualitativa para un dato ordenado. El lector no puede deducir el orden y tiene que memorizar la leyenda.
El arcoíris en un mapa de calor. Luminosidad no monótona: crea fronteras que los datos no tienen y esconde cambios donde sí los hay.
Rojo y verde como único par. Ilegible para una parte apreciable de los lectores. Naranja y azul hacen el mismo trabajo.
Las categorías en orden alfabético. Ordenar por valor es la mejora más barata que existe, salvo en los tres casos donde el orden significa algo.
Un apilado donde la pregunta es sobre la serie del medio. Solo la serie inferior tiene línea base común; las demás flotan y no se pueden comparar.
Suavizar una serie discreta. Una curva suave afirma que hubo valores intermedios. Con curveBasis, además, la curva ni siquiera pasa por los datos.
El título describe los ejes. Un título sin verbo no dice nada que las etiquetas no dijeran ya.
Una leyenda con cuatro entradas. El etiquetado directo elimina el bucle de consulta y libera el color como canal.
Pequeños múltiplos con escala por panel y sin avisar. El lector asume escala compartida y compara alturas que no son comparables.
Rendimiento, accesibilidad y arquitectura
Diez mil nodos SVG que se mueven. El coste por nodo domina. La respuesta es un lienzo para los datos, no trucos para reducir nodos, que acaban en el mismo sitio renunciando a lo que hacía valioso el SVG.
Un filtro por elemento. Cien elementos con sombra pueden costar más que diez mil sin ella. El filtro va en el grupo.
getImageData en el bucle de dibujado sin willReadFrequently. Fuerza una sincronización con la GPU en cada llamada. La opción es obligatoria en el lienzo de aciertos y contraproducente en el visible.
Aciertos fantasma en la selección por color. Alfa distinto de 255, antialiasing en los bordes, o lectura sin multiplicar por el ratio. Los tres están en la interacción.
Un ResizeObserver que nadie desconecta. Mantiene vivo el contenedor entero. Toda función de montaje debe devolver una de destrucción.
Elementos duplicados tras actualizaciones rápidas. Nodos con una transición de salida pendiente que el siguiente join vuelve a capturar. Está en el join de datos.
Un lienzo sin contenido alternativo. No hay nada que leer, nada que buscar, nada que traducir. La tabla dentro del elemento es el único canal.
El color como único canal para distinguir series. Falla con deficiencia de visión del color, en escala de grises y en una fotocopia.
import * as d3 con acceso dinámico a propiedades. Impide la eliminación de código muerto y arrastra el paquete entero.
Dos rutas de renderizado que calculan cada una por su lado. Divergen, y nadie se entera hasta que alguien pone las dos imágenes juntas.
Medición de texto dentro de la capa de cálculo. Rompe la pureza y con ella el render en servidor y las pruebas sin navegador.
Vuelve a mirar las cuatro secciones. Las de geometría, SVG y rendimiento comparten una propiedad: producen un síntoma observable. Algo se ve mal, algo va lento, algo no aparece. Con tiempo suficiente, cualquiera los encuentra, y una prueba automática los puede atrapar: una comparación visual detecta el desplazamiento de medio píxel, una prueba unitaria detecta el NaN del dominio degenerado, un presupuesto de rendimiento detecta los diez mil nodos.
La tercera sección no. Un gráfico de barras con el eje truncado se dibuja perfectamente, pasa todas las pruebas, tiene el mismo aspecto que uno correcto para quien no está mirando el eje, y comunica algo falso. No hay herramienta que lo detecte, porque no hay nada roto: hay una decisión mal tomada.
Esa asimetría tiene tres consecuencias prácticas que conviene interiorizar.
Los errores de representación necesitan revisión humana, y una lista. No basta con «revisar el gráfico»: hace falta pasar una lista concreta. Cuatro preguntas atrapan la mayoría: ¿empieza el eje en cero y debería, o al revés? ¿de qué color sale el valor cero? ¿está la variable principal en el mejor canal disponible? ¿tiene el título un verbo? Cuatro preguntas, treinta segundos, y cubren la mayor parte de la tercera sección.
Los errores de representación se cometen sobre todo por prisa, no por ignorancia. Casi todo el mundo que trunca un eje sabe que no debería. Lo hace porque la diferencia no se ve y hay que enseñar el gráfico en una hora. Por eso la defensa no es formación: es que el valor por defecto de tu código sea el correcto. Que tu componente de barras empiece en cero salvo que le pidas lo contrario, y que pedirlo requiera escribir una opción con un nombre incómodo.
Los errores de representación son los únicos que tienen consecuencias fuera del software. Un gráfico borroso molesta. Un gráfico con un eje dual mal elegido puede sostener una decisión de negocio equivocada durante un año. La proporción entre lo que cuesta cometerlos y lo que cuestan es la peor de toda la lista.
Y el hábito que resume todo el catálogo, y que es lo último que te va a hacer falta de este track: mira tu gráfico como si lo hubiera hecho otro y quisiera convencerte de algo. Busca dónde empieza el eje, de qué color es el cero, qué escala tiene el panel de al lado, y qué pasaría si ordenaras las categorías al revés. Con esa mirada, los quince errores de la tercera sección aparecen en un minuto, y sin ella no aparecen nunca.
Coge los tres gráficos más visibles de tu producto y pásales las cuatro preguntas de la lista corta del callout. Anota los fallos y, para cada uno, decide si su causa fue desconocimiento o prisa. Después cambia el valor por defecto del componente correspondiente para que el fallo por prisa deje de ser posible: esa es la única corrección que no hay que repetir.