【问题标题】: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?D3.js:有没有办法将“显示”值限制在轴最大值/最小值,同时保留工具提示显示的“实际”值?
【发布时间】:2021-12-24 06:12:39
【问题描述】:

更新(21 年 11 月 19 日):添加了其他解决方案

你们中的大多数人可能不记得我之前的问题Circles not updating correctly for multiline charts with two-level nested data。我设法在那里找出/解决了我的问题(尽管我仍然不相信我想出的东西是 100% 正确的);不过,我现在还有一个问题。

我的 y 轴数据 (d.mval) 具有极端异常值。结果,我的图表被压缩了,有相当多的空白。例如,请参阅此 JSFiddle 中的“现金流”图表:https://jsfiddle.net/etonblue/a98m52k4/3/。我尝试了中位数、平均值、平均值、标准差等的各种组合来尝试设置域,但还没有找到一个对我的所有数据都有效的解决方案。所以我对我的域进行了硬编码:

    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 轴。

我的问题是,有没有办法使用 D3 将 显示的 值限制在域的最大/最小值,同时保留 实际 值(以便工具提示显示实际值而不是显示值)?

我目前正在使用 d3.v4。

更新

在此处更新小提琴(使用解决方案 3):https://jsfiddle.net/etonblue/6v924ory/2/

更新二 至少三种不同的方法:

  1. 在绘制之前计算线与轴的交点。

  2. 使用剪辑路径,例如,在轴下创建一个与背景颜色相同的矩形,并按以下顺序绘制:数据 -> 矩形 -> 轴。例如:

svg.append("rect")
    .attr("height",margin.bottom)
    .attr("width",width)
    .attr("x",0)
    .attr("y",height-margin.bottom)
    .attr("fill","#c0ffee")
  1. 将传递给 line 函数中轴的值与域的值进行比较(下面的代码将 y 轴值(在本例中为 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 所指出的,上述每个解决方案的视觉结果都会略有不同:

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    您提供的代码与解决方案不太相关。从您的小提琴开始,解决方案是在您的直线和圆的 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 方式。因为我有十个不同的图,每个图都有自己的域(并且必须通过检查哪个图处于活动状态来检查哪个域),你漂亮的条件三元组最终会变得非常混乱。我已经编辑了上面的帖子以包含新的代码块。
    • 我已经更新了我的答案。
    • 解决方案在 SmokeyShakers 的更新答案中,它确实既“干净”又是“d3 方式”。请参阅上面编辑过的帖子。
    【解决方案2】:

    这不仅仅是 d3 刻度所需的 clamp() 选项吗?这将停止域 --> 范围转换超出范围的最小值/最大值。

    https://github.com/d3/d3-scale#continuous_clamp

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-25
      相关资源
      最近更新 更多