2016-03-31 16 views
1

Şu anda bir d3 projesi üzerinde çalışıyorum ve hem pozitif hem de negatif büyük değerler aralığıyla çubuk grafikler göstermeye çalışıyorum.d3js - Özel ölçek oluştur - Pozitif ve negatif logaritma

d3.scale.sqrt() numaralı telefonu kullanarak çevrimiçi bir çözüm gördüm veya iki günlük ölçeği görüntüledim ancak kendi ölümü oluşturabilir miyim diye merak ediyordum.

Aklımda olan şey, negatif değerler için bir günlük ölçeği, [-e, e] ve pozitif değerler için normal bir günlük ölçeği arasındaki değerler için doğrusal bir ölçek arasındaki bir karışımdır. Bu gibi görünebilir şey: http://img15.hostingpics.net/pics/12746197ln.png

y = -log(-x) if x < -e 
y = x/e  if -e <= x <= e 
y = log(x) if x > e 

mı mümkün olabileceğini düşünüyorsun? Ayrıca özetlemek için bir JSFiddle oluşturdum.

sayesinde

cevap

0

Burada bulduğu çözüm: JSFiddle

Olabilir garip bir şekilde, ama ben iyileştirilmesine dair tavsiyeler herhangi parçalarını varsa, çekinmeyin, düşünmek çalışıyor. Sanırım hatalar yaptım, özellikle kütük ve keneler üzerinde.

Burada, d3.js'nin kendisine dayalı olarak oluşturduğum işlev var.

(function() { 
    scalepnlog = { 
    init: function(){ 
     return d3_scale_pnlog(d3.scale.linear().domain([ 0, 1 ]), [ 1, 10 ]); 
    } 
    } 
    function d3_scaleExtent(domain) { 
    var start = domain[0], stop = domain[domain.length - 1]; 
    return start < stop ? [ start, stop ] : [ stop, start ]; 
    } 
    var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { 
    floor: function(x) { 
     return -Math.ceil(-x); 
    }, 
    ceil: function(x) { 
     return -Math.floor(-x); 
    } 
    }; 
    function sign(x){ 
    return x >= 0 ? 1:-1; 
    } 


    function d3_scale_pnlog(linear, domain) { 
    function pnlog(x) { 
     return (x >= Math.E || x <= -Math.E) ? sign(x)*Math.log(Math.abs(x)) : x/Math.E; 
    } 
    function pnpow(x) { 
     return (x >= 1 || x <= -1)? sign(x)*Math.pow(Math.E,Math.abs(x)) : Math.E*x; 
    } 
    function scale(x) { 
     return linear(pnlog(x)); 
    } 
    scale.invert = function(x) { 
     return pnpow(linear.invert(x)); 
    }; 
    scale.domain = function(x) { 
     if (!arguments.length) return domain; 
     linear.domain((domain = x.map(Number)).map(pnlog)); 
     return scale; 
    }; 
    scale.nice = function() { 
     var niced = d3_scale_nice(domain.map(pnlog), positive ? Math : d3_scale_logNiceNegative); 
     linear.domain(niced); 
     domain = niced.map(pow); 
     return scale; 
    }; 
    scale.ticks = function() { 
     var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(pnlog(u)), j = Math.ceil(pnlog(v)), n = 10 % 1 ? 2 : 10; 
     if (isFinite(j - i)) { 
     for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pnpow(i) * k); 
     ticks.push(pnpow(i)); 
     for (i = 0; ticks[i] < u; i++) {} 
     for (j = ticks.length; ticks[j - 1] > v; j--) {} 
     ticks = ticks.slice(i, j); 
     } 
     return ticks; 
    }; 
    scale.tickFormat = function(n, format) { 
     if (!arguments.length) return d3_scale_logFormat; 
     if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); 
     var k = Math.max(1, 10 * n/scale.ticks().length); 
     return function(d) { 
     var i = d/pnpow(Math.round(pnlog(d))); 
     if (i * 10 < 10 - .5) i *= 10; 
     return i <= k ? format(d) : ""; 
     }; 
    }; 
    scale.copy = function() { 
     return d3_scale_pnlog(linear.copy(), domain); 
    }; 
    return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); 
    } 
})(); 

Gerçekten ne yaptığımı bilmiyorum ama temelde, onun karşılıklı pnlog ve pnpow yarattı ve işe yaradı kadar gerekli farklı d3 fonksiyonları eklendi. İşte

onlar:

function pnlog(x) { 
    return (x >= Math.E || x <= -Math.E) ? sign(x)*Math.log(Math.abs(x)) : x/Math.E; 
} 

ve

function pnpow(x) { 
    return (x >= 1 || x <= -1)? sign(x)*Math.pow(Math.E,Math.abs(x)) : Math.E*x; 
}