使用d3.js是否有方法将两个Y轴与正值和负值进行零对齐

fd3cxomn  于 2023-05-07  发布在  其他
关注(0)|答案(2)|浏览(107)

我是D3的新手,学到了很多东西。我有一个问题,我找不到一个例子:我有两个y轴,分别是正值和负值,它们的域有很大的不同,一个是大金额,另一个是百分比。
从拼凑在一起的例子得到的图形看起来真的很棒,有一个轻微的细节,每个y轴的零线在一个稍微不同的位置。有谁知道d3中的一种方法,可以使零线位于相同的x位置吗?
我希望这两个yScale/轴共享同一零线

// define yScale
var yScale = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(dataset, function(d) { return d.value_di1; }))
;

// define y2 scale
var yScale2 = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(dataset, function(d) { return d.calc_di1_di2_percent; }))
;

下面是一个带有示例数据的jsfiddle链接:
http://jsfiddle.net/jglover/XvBs3/1/
(the jsfiddle示例中的x轴刻度看起来很可怕)

c90pui9n

c90pui9n1#

一般来说,很不幸,没有办法做到这一点整洁。D3并没有真正的概念,几件事排队,因此没有办法完成它。
然而,在您的特定情况下,您可以通过调整第二个y轴的域来轻松修复它:

.domain([d3.min(dataset, function(d) { return d.calc_di1_di2_percent; }), 0.7])

完整的示例here

liwlm1x9

liwlm1x92#

为了使0水平处于相同的位置,策略是使y轴的长度/比例相等。以下是解决方案的概念:
1.基线的对齐取决于y轴的长度。
1.为了让所有值显示在条形图中,我们需要延长尺寸的较短侧,与另一侧进行比较,以使两个轴的比例相等。
例如:

// dummy data
const y1List = [-1000, 120, -130, 1400],
    y2List = [-0.1, 0.2, 0.3, -0.4];

// get proportion of the two y axes
const totalY1Length = Math.abs(d3.min(y1List)) + Math.abs(d3.max(y1List)),
    totalY2Length = Math.abs(d3.min(y2List)) + Math.abs(d3.max(y2List)),
    maxY1ToY2 = totalY2Length * d3.max(y1List) / totalY1Length,
    minY1ToY2 = totalY2Length * d3.min(y1List) / totalY1Length,
    maxY2ToY1 = totalY1Length * d3.max(y2List) / totalY2Length,
    minY2ToY1 = totalY1Length * d3.min(y2List) / totalY2Length;

// extend the shorter side of the upper dimension with corresponding value
let maxY1Domain = d3.max(y1List),
    maxY2Domain = d3.max(y2List);
if (maxY1ToY2 > d3.max(y2List)) {
    maxY2Domain = d3.max(y2List) + maxY1ToY2 - d3.max(y2List);
} else {
    maxY1Domain = d3.max(y1List) + maxY2ToY1 - d3.max(y1List);
}

// extend the shorter side of the lower dimension with corresponding value
let minY1Domain = d3.min(y1List),
    minY2Domain = d3.min(y2List);
if (minY1ToY2 < d3.min(y2List)) {
    minY2Domain = d3.min(y2List) + minY1ToY2 - d3.min(y2List);
} else {
    minY1Domain = d3.min(y1List) + minY2ToY1 - d3.min(y1List);
}

// finally, we get the domains for our two y axes
const y1Domain = [minY1Domain, maxY1Domain],
    y2Domain = [minY2Domain, maxY2Domain];

相关问题