Escalas lineales en d3 e interacción con los datos mapeados con d3.invert()

En gráficos de tipo time-series como en contratos menores se exponen datos en dos ejes. El eje X, suele representar el tiempo en alguna medida (día,mes, año, etc) y en el eje Y se presenta una cantidad abstracta. En la mayoría de los casos se tiene que hacer un ´mapping´ de estos datos para convertir la cantidad abstracta (aqui dinero en miles de €) en píxeles segun las dimensiones que queremos que tenga nuestro grafico. Existen muchas manera de hacer el mapping con la lineal siento la mas común cuanto se expone datos de dinero.

D3js tiene unas funciones que permiten mapear una serie de numeros a una otra de manera linear:

var x = d3.scaleLinear().domain([10, 130]).range([0, 960]);

En el ejemplo se ha definido una función x. Unos datos que están entre 10 y 130 se mapean en una escala de 0 a 960.

Esa función la podemos utilizar de la siguiente manera.

x(10);

<- 0

x(130);

<- 960

x(70);

<- 480

x(2);

<- -64

Se puede observar que dando un numero fuera de rango del .domain() se devuelve un valor negativo. Finalmente la funcion X representa una manera de proyectar un valor de una escala lineal a una otra.

La función x se puede también invertir con x.invert() que seria en realidad como hacer :

var y = d3.scaleLinear().domain([0, 960]).range([10, 130]);
o hacer:
x.invert()

Pero utilizando .invert() tiene la ventaja, aparte la economía de código, podemos tener un mapeo que no sea fijo, si por ejemplo tenemos un gráfico que cambia sus dimensiones según el tamaño de la pantalla. .invert() nos asegura que la inversión sera correcta.

Resulta muy cómodo a la hora de interactuar con los datos. Se pueden obtener la cantidad inicial para imprimir la en la pantalla p.ej. En seguida veremos como hemos aprovechado de esa funcionalidad para calcular el importe en dinero de todas las barras activas en el grafico de contratos menores.

Una vez aplicados unos filtros de empresa, centro de gasto o categoria de gastos, en nuestro grafico aparecen los que cumplen estos filtros.

barrasActivas = d3.selectAll(‘svg .bar’+ filters);

Cada barra tiene un attributo height que ha sido calculado con el scaleLinear() como en el ejemplo arriba. haciendo la inversion con :

altura = barrasActivas.attr(‘height’); // Leer la altura en pixeles

dinero = yScale.invert(altura) // Revesar la operación que mapeo el importe del contrato en una altura en píxeles

Haciendo una repetitiva se puede sumar los importes de todas la barras activas y imprimir la en la pantalla.