D3:抛物线"抛物线"可能的尺度?

时间:2017-05-26 17:35:14

标签: javascript d3.js data-visualization

我正在制作一张图表,每张图表的值都在[-100,100]之间,我想在一个刻度上绘制每个点的位置。挑战在于绝大多数点在一个区域内具有值(分布基本上是高斯分布,均值为0)。

过去,当我需要绘制类似Zipf概率密度分布的东西时,我已经使用对数尺度来展开拥挤区域中的点。现在我的情况类似,除了我有两个分布,我需要分散点(从[0,最大]的正标度和从[0,min]的镜像负标度)。

我知道我可以为正值创建一个刻度,为负值创建一个刻度,但我想知道是否可以仅使用一个刻度来实现此布局。似乎抛物线尺度的东西可以在这里帮助(如果存在的话)。在D3中有可能实现这样的效果吗?

1 个答案:

答案 0 :(得分:3)

在解释我提出的解决方案之前,请先考虑一下这个问题中的评论:不能在您的情况下使用对数比例。这是一个简单的数学原理:Log(0)是负无穷大。实际上,这在docs

中明确说明
  

当log(0)=-∞时,对数标度域必须是严格为正或严格为负;域名不得包含或交叉零。

话虽如此,让我们转到建议的解决方案。

您可以创建自己的比例(它并不复杂)。但是,在这里,我将使用基于此interpolateexcellent answer函数(但不是重复,因为您需要相反的)和此code from Mike Bostock

使用线性刻度,我们设置插值器:

var xScale = d3.scaleLinear()
    .domain([-100, 100])
    .interpolate(easeInterpolate(d3.easeQuadInOut));

然后,我们在easeInterpolate函数中使用easing

function easeInterpolate(ease) {
    return function(a, b) {
        var i = d3.interpolate(a, b);
        return function(t) {
            return i(ease(t));
        };
    };
}

我在这里使用d3.easeQuadInOut,我认为这适合您,但您可以将其更改为另一个,甚至创建自己的。

看看这个演示。我创建了50个圆圈,从-100到+100(-100,-96,-92,-88 ......直到+100)均匀分布。你可以看到他们从中心搬走了。如果您将此比例与数据一起使用,则可以避免拥挤的数据点在零附近:



var data = d3.range(51).map(function(d) {
  return -100 + (d * 4)
});

var svg = d3.select("body")
  .append("svg")
  .attr("width", 600)
  .attr("height", 100);

var xScale = d3.scaleLinear()
  .domain([-100, 100])
  .range([20, 580])
  .interpolate(easeInterpolate(d3.easeQuadInOut));

svg.append("g")
  .attr("transform", "translate(0,70)")
  .call(d3.axisBottom(xScale));

svg.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return xScale(d)
  })
  .attr("cy", 50)
  .attr("r", 4)
  .attr("fill", "teal")

function easeInterpolate(ease) {
  return function(a, b) {
    var i = d3.interpolate(a, b);
    return function(t) {
      return i(ease(t));
    };
  };
}

<script src="https://d3js.org/d3.v4.min.js"></script>
&#13;
&#13;
&#13;

如果你问,最后一个勾号不是80100。这只是80刻度与100刻度重叠(-80-100也是如此)。

另外,值得注意的是,使用变换后的刻度并没有错,即使它变形倾斜图表,它也是如此完全有效且不会导致误解,只要您告知用户有关转换。