2012-04-25 28 views
9

Estoy usando d3.format ("s") con d3.svg.axis.tickFormat para formatear muy bien las etiquetas de tics con unidades SI (del Sistema Internacional de Unidades). Funciona muy bien en su mayor parte, a excepción de ciertos valores que se ejecutan en un error de redondeo y devuelve una tonelada de decimales (1400, por ejemplo, como 1400 * 0.001 = 1.4000000000000001).Precisión de la variable en d3.format

Para evitar esto puedo especificar una precisión, como d3.format (".2s") pero esto fuerza 2 dígitos significativos en los casos en que 1 sería mejor. Por ejemplo, si tengo ticks [5000, 10000, 15000], ahora vería [5.0k, 10k, 15k]. Originalmente, cuando no especificaba la precisión, obtuve [5k, 10k, 15k].

Me pregunto si es posible especificar una precisión máxima de modo que solo se aplique cuando el número de dígitos significantes excede el número especificado. Entonces 5000 serían 5k y no 5.0k.

Respuesta

2

Puede hacer esto colocando una instrucción if/else en una función anónima donde se mostraría la cadena de texto. Dentro de ese if/else puede satisfacer cualquier condición que desee y crear una función que analiza su valor. Aquí hay un ejemplo:

var w = 30, h = 300; 
var data = [ 
    {'point':1, 'value':100.005}, 
    {'point':2, 'value':20.010}, 
    {'point':3, 'value':1000}, 
    {'point':4, 'value':5000.099}, 
    {'point':5, 'value':6000.934}, 
    {'point':6, 'value':9000.888}, 
    {'point':7, 'value':500.22}, 
    {'point':8, 'value':5.123}, 
    {'point':9, 'value':50.022}, 
    {'point':10, 'value':7000.999} 
]; 
var chart = d3.select("body").append("svg") 
    .attr('class', 'chart') 
    .attr("width", w * data.length - 1) 
    .attr("height", h); 

chart.selectAll('text') 
    .data(data) 
.enter().append('text') 
    .attr('x', function(d, i) { return x(i); }) 
    .attr('y', function(d) { return h - y(d.value); }) 
    .attr('dx', '0.75em') 
    .attr('dy', '-0.3em') 
    .attr('text-anchor', 'start') 
    .text(function(d) { 
    if(d.value > 5000) { 
     // Define your formatting function to return SI units 
     var si = d3.format('s'); 
     return String(si(d.value)); 
    } else { 
     // Otherwise round to the nearest integer 
     return String(d3.round(d.value, 0)); 
    } 
    }); 

Espero que ayude.

+0

Gracias por la respuesta. Lamentablemente, estoy usando el helper d3.svg.axis para que los valores que estoy formateando sean valores de tilde, no valores de datos. El formateo se realiza internamente a medida que se generan las etiquetas tic. Podría envolver la función devuelta desde d3.format en mi propia función para interceptar los valores, pero volver a analizar la cadena devuelta desde el formateador SI no parece demasiado limpia. Me preguntaba si podría haber algo incorporado en el formateador para soportar esto sin codificarlo yo mismo. –

+0

Ahh bien. Mi código es para las etiquetas de datos, no para las etiquetas. Espero no haberlo guiado por el camino equivocado. ¿Podría hacer algo similar, pero con las funciones de etiquetado de ticks (es decir, pasarles una función anónima)? – tatlar

2

Mientras que 1400 * .001 es 1.4000000000000001, 1400/1000 es 1.4; multiplicar un número entero por una potencia negativa de diez (como .001) puede introducir un error de redondeo, pero parece que dividir un número entero por una potencia de diez (por ejemplo, 1000) no lo hace. O al menos, es menos probable? Implementé una corrección tentativa en la rama de reparación de formato de formato de si. Es estrictamente incompatible con versiones anteriores, pero como la función d3.formatPrefix no está documentada, creo que sería seguro incluirla en la próxima versión del parche.

Editar: Esta revisión se lanzó en la versión 2.9.2.

+0

Interesante que esas dos operaciones producen resultados diferentes. No lo habría adivinado. Mantendré mis ojos bien abiertos para esta solución en el próximo parche. ¡Gracias! –