我正在制作一张图表,每张图表的值都在[-100,100]之间,我想在一个刻度上绘制每个点的位置。挑战在于绝大多数点在一个区域内具有值(分布基本上是高斯分布,均值为0)。
过去,当我需要绘制类似Zipf概率密度分布的东西时,我已经使用对数尺度来展开拥挤区域中的点。现在我的情况类似,除了我有两个分布,我需要分散点(从[0,最大]的正标度和从[0,min]的镜像负标度)。
我知道我可以为正值创建一个刻度,为负值创建一个刻度,但我想知道是否可以仅使用一个刻度来实现此布局。似乎抛物线尺度的东西可以在这里帮助(如果存在的话)。在D3中有可能实现这样的效果吗?
答案 0 :(得分:3)
在解释我提出的解决方案之前,请先考虑一下这个问题中的评论:不能在您的情况下使用对数比例。这是一个简单的数学原理:Log(0)是负无穷大。实际上,这在docs:
中明确说明当log(0)=-∞时,对数标度域必须是严格为正或严格为负;域名不得包含或交叉零。
话虽如此,让我们转到建议的解决方案。
您可以创建自己的比例(它并不复杂)。但是,在这里,我将使用基于此interpolate的excellent 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;
如果你问,最后一个勾号不是80100
。这只是80
刻度与100
刻度重叠(-80
和-100
也是如此)。
另外,值得注意的是,使用变换后的刻度并没有错,即使它变形或倾斜图表,它也是如此完全有效且不会导致误解,只要您告知用户有关转换。