2012-04-25 12 views
9

Sto utilizzando d3.format ("s") con d3.svg.axis.tickFormat per formattare in modo preciso le etichette di graduazione con unità SI (dal Sistema internazionale di unità). Funziona magnificamente per la maggior parte, tranne alcuni valori che si imbattono in un errore di arrotondamento e restituiscono una tonnellata di cifre decimali (1400, ad esempio, 1400 * 0,001 = 1,4000000000000001).Precisione variabile in d3.format

Per aggirare questo, è possibile specificare una precisione, ad esempio d3.format (". 2s"), ma ciò impone 2 cifre significative nei casi in cui 1 sarebbe migliore. Ad esempio, se ho tick [5000, 10000, 15000] vedrei ora [5.0k, 10k, 15k]. Inizialmente, quando non ho specificato la precisione, ho ottenuto [5k, 10k, 15k].

Mi chiedo se è possibile specificare una precisione massima tale che verrà applicata solo quando il numero di cifre significative supera il numero specificato? Quindi 5000 sarebbero 5k e non 5,0k.

risposta

2

È possibile eseguire questa operazione inserendo un'istruzione if/else in una funzione anonima in cui si invierà la stringa di testo. All'interno di questo se/else è possibile soddisfare qualsiasi condizione che si desidera e creare una funzione che analizza il valore. Ecco un esempio:

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)); 
    } 
    }); 

Sperare che aiuti.

+0

Grazie per la risposta. Sfortunatamente, sto usando l'helper d3.svg.axis in modo che i valori che sto formattando siano valori di tick, non valori di dati. La formattazione viene eseguita internamente quando vengono generate le etichette di graduazione. Potrei avvolgere la funzione restituita da d3.format nella mia funzione per intercettare i valori ma ri-analizzare la stringa restituita dal formattatore SI non sembra troppo pulita. Mi stavo chiedendo che ci potrebbe essere qualcosa di integrato nel formattatore per supportare questo senza codificarlo da solo. –

+0

Ahh giusto. Il mio codice è per le etichette dei dati, non le etichette di graduazione. Spero di non averti guidato sulla strada sbagliata. Potresti fare qualcosa di simile, ma con le funzioni di etichettatura dei segni di graduazione (ad esempio, passargli una funzione anonima)? – tatlar

2

Mentre 1400 * .001 è 1.4000000000000001, 1400/1000 è 1.4; moltiplicando un numero intero con una potenza negativa di dieci (come .001) si può introdurre un errore di arrotondamento, ma sembra che dividere un numero intero con una potenza di dieci (come 1000) non lo sia. O almeno, è meno probabile? Ho implementato una correzione provvisoria nel ramo di arrotondamento fix-si-format. È strettamente incompatibile con le versioni precedenti, ma dal momento che la funzione non è documentata, penso che sarebbe sicuro includere nella prossima versione di patch.

Modifica: questa correzione è stata rilasciata nella versione 2.9.2.

+0

Interessante che queste due operazioni producano risultati diversi. Non l'avrei immaginato. Terrò gli occhi aperti per questa correzione nella prossima patch. Grazie! –