【问题标题】:d3js - Create custom scale - Positive and negative logarithmd3js - 创建自定义比例 - 正负对数
【发布时间】:2016-03-31 09:31:37
【问题描述】:

我目前正在处理一个 d3 项目,我正在尝试显示具有大量值(正值和负值)的条形图。

我在网上看到使用d3.scale.sqrt() 或显示两个对数刻度的漫游,但我想知道是否可以创建自己的刻度。

我想到的是负值的对数刻度、[-e, e] 之间的值的线性刻度和正值的常规对数刻度之间的混合。 可能看起来像这样的东西: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

你认为这可能吗? 我还创建了一个JSFiddle 来总结一下。

谢谢,

【问题讨论】:

    标签: javascript d3.js scale logarithm


    【解决方案1】:

    这是我找到的一种解决方案:JSFiddle

    这可能是一种奇怪的方式,但我认为它很有效,如果您有任何改进建议,请不要犹豫。我认为我犯了错误,尤其是在对数基础和滴答声上。

    这是我创建的函数,基于 d3.js 本身。

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

    我真的不知道自己在做什么,但基本上,我创建了 pnlogpnpow,它们的倒数,并添加了所需的不同 d3 函数,直到它工作为止。

    他们在这里:

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

    【讨论】:

      猜你喜欢
      • 2014-01-16
      • 2018-07-23
      • 2013-01-24
      • 2013-06-19
      • 2013-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多