D3.js:有没有办法在轴 max/min 处限制 "displayed" 值,同时保留工具提示显示的 "actual" 值?
D3.js: Is there a way to cap a "displayed" value at an axis max/min while retaining the "actual" value for a tooltip display?
更新 (11/19/21):添加了其他解决方案
你们中的大多数人可能不记得我之前的问题 Circles not updating correctly for multiline charts with two-level nested data。我设法 out/work 解决了我的问题(尽管我仍然不相信我想出的是 100% 正确的);但是,我现在有另一个问题。
我的 y-axis 数据 (d.mval) 具有极端异常值。结果,我的图表被压缩了,有相当多的空白 space。例如,请参阅此 JSFiddle 中的“现金流”图表:https://jsfiddle.net/etonblue/a98m52k4/3/。我已经尝试了中位数、均值、平均值、标准差等的各种组合来尝试设置域,但还没有找到对我的所有数据都能一致工作的解决方案。所以我求助于 hard-coding 我的域名:
if (val == 1) {ydom = [-2,20]}
else if (val == 2) {ydom = [-40,240]}
else if (val == 3) {ydom = [-.5,1.5]}
else if (val == 4) {ydom = [-.6,.9]}
else if (val == 5) {ydom = [-.6,.6]}
else if (val == 6) {ydom = [-.16,.16]}
else if (val == 7) {ydom = [-.5,3]}
else if (val == 8) {ydom = [-1000000,2000000]}
else if (val == 9) {ydom = [-1000000,2000000]}
else if (val == 10) {ydom = [-4,10]}
这不仅丑陋,还意味着现在任何极值都远高于或远低于我显示的 y-axis。
我的问题是,有没有一种方法可以使用 D3 在域的 max/min 处限制 displayed 值,同时保留 actual 值(以便工具提示显示实际值而不是显示值)?
我目前使用的是 d3.v4。
更新
在此处更新了 fiddle(使用解决方案 3):https://jsfiddle.net/etonblue/6v924ory/2/。
更新二
至少三种不同的方法:
在绘制之前计算直线与轴的交点。
使用裁剪路径,例如在坐标轴下创建一个与背景颜色相同的矩形,按照数据->矩形->坐标轴的顺序绘制。例如:
svg.append("rect")
.attr("height",margin.bottom)
.attr("width",width)
.attr("x",0)
.attr("y",height-margin.bottom)
.attr("fill","#c0ffee")
- 将传递给线函数中的轴的值与域的值(下面的代码上限为 y-axis 值(在本例中为:d.mval)进行比较( y.domain()[0]) 或域的最大 (y.domain()[1]) 值,同时不更改 d.mval 的实际值:
var line = d3.line()
.x(d => x(d.year))
.y(d => d.mval < y.domain()[0] ? y(y.domain()[0]) : d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval))
和
.attr("cx", d => x(d.year))
.attr("cy", d => d.mval < y.domain()[0] ? y(y.domain()[0]) : d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval))
重要说明:正如 d3 slack 组中的 Matt Dzugan 所指出的,上述每个解决方案的视觉效果都会略有不同:
您提供的代码与解决方案不太相关。从您的 fiddle 开始,解决方案就在您对直线和圆圈的 y 位置的回调中。对于您的线路:
var line = d3.line()
.x(d => x(d.year))
.y(d => d.mval > 240 ? y(240) : y(d.mval)) //If mval is over 240 plot 240
同样适用于您的圈子 cy:
.attr('cy', d => d.mval > 240 ? y(240) : y(d.mval))
更一般地,您可以使用回调:
d => d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval)
我不会放弃了解你的设置,
d3 比例尺需要的不仅仅是 clamp() 选项吗?这将停止域 --> 范围转换超过范围的 min/max。
更新 (11/19/21):添加了其他解决方案
你们中的大多数人可能不记得我之前的问题 Circles not updating correctly for multiline charts with two-level nested data。我设法 out/work 解决了我的问题(尽管我仍然不相信我想出的是 100% 正确的);但是,我现在有另一个问题。
我的 y-axis 数据 (d.mval) 具有极端异常值。结果,我的图表被压缩了,有相当多的空白 space。例如,请参阅此 JSFiddle 中的“现金流”图表:https://jsfiddle.net/etonblue/a98m52k4/3/。我已经尝试了中位数、均值、平均值、标准差等的各种组合来尝试设置域,但还没有找到对我的所有数据都能一致工作的解决方案。所以我求助于 hard-coding 我的域名:
if (val == 1) {ydom = [-2,20]}
else if (val == 2) {ydom = [-40,240]}
else if (val == 3) {ydom = [-.5,1.5]}
else if (val == 4) {ydom = [-.6,.9]}
else if (val == 5) {ydom = [-.6,.6]}
else if (val == 6) {ydom = [-.16,.16]}
else if (val == 7) {ydom = [-.5,3]}
else if (val == 8) {ydom = [-1000000,2000000]}
else if (val == 9) {ydom = [-1000000,2000000]}
else if (val == 10) {ydom = [-4,10]}
这不仅丑陋,还意味着现在任何极值都远高于或远低于我显示的 y-axis。
我的问题是,有没有一种方法可以使用 D3 在域的 max/min 处限制 displayed 值,同时保留 actual 值(以便工具提示显示实际值而不是显示值)?
我目前使用的是 d3.v4。
更新
在此处更新了 fiddle(使用解决方案 3):https://jsfiddle.net/etonblue/6v924ory/2/。
更新二 至少三种不同的方法:
在绘制之前计算直线与轴的交点。
使用裁剪路径,例如在坐标轴下创建一个与背景颜色相同的矩形,按照数据->矩形->坐标轴的顺序绘制。例如:
svg.append("rect")
.attr("height",margin.bottom)
.attr("width",width)
.attr("x",0)
.attr("y",height-margin.bottom)
.attr("fill","#c0ffee")
- 将传递给线函数中的轴的值与域的值(下面的代码上限为 y-axis 值(在本例中为:d.mval)进行比较( y.domain()[0]) 或域的最大 (y.domain()[1]) 值,同时不更改 d.mval 的实际值:
var line = d3.line()
.x(d => x(d.year))
.y(d => d.mval < y.domain()[0] ? y(y.domain()[0]) : d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval))
和
.attr("cx", d => x(d.year))
.attr("cy", d => d.mval < y.domain()[0] ? y(y.domain()[0]) : d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval))
重要说明:正如 d3 slack 组中的 Matt Dzugan 所指出的,上述每个解决方案的视觉效果都会略有不同:
您提供的代码与解决方案不太相关。从您的 fiddle 开始,解决方案就在您对直线和圆圈的 y 位置的回调中。对于您的线路:
var line = d3.line()
.x(d => x(d.year))
.y(d => d.mval > 240 ? y(240) : y(d.mval)) //If mval is over 240 plot 240
同样适用于您的圈子 cy:
.attr('cy', d => d.mval > 240 ? y(240) : y(d.mval))
更一般地,您可以使用回调:
d => d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval)
我不会放弃了解你的设置,
d3 比例尺需要的不仅仅是 clamp() 选项吗?这将停止域 --> 范围转换超过范围的 min/max。