gpt4 book ai didi

d3.js - 如何在 d3 中在两条不同长度(不同 x 值)的曲线之间绘制区域/填充

转载 作者:行者123 更新时间:2023-12-03 20:49:57 25 4
gpt4 key购买 nike

问题
我正在尝试构建一个折线图,在其中我在两条线之间着色(根据哪条线在另一条线上方不同颜色)。这非常适用于所有测试情况下的线性曲线。
但是,这需要使用实际曲线(例如 curveBasis ,如下所示)。如果线条具有完全相同的 x 值,这将非常有效;但我们有这样的情况:a) 一条线比另一条线长/短和/或 b) 一条线可能在该线的中间丢失一个或多个 x 值,而另一条线没有丢失。这是因为在两点之间绘制一条线的方式会根据非线性时之前/之后的点而变化。
一般来说,我明白为什么会这样;但是我很难找到一个很好的解决方案来使它真正按照我想要的方式工作。我很想至少被指出正确的方向或给出一些想法(我考虑过的一个想法列在底部)!
例子
以下是它如何与 curveLinear 一起使用(看起来挺好的):
How it works with curve linear (straight lines)
这是 curveBasis 的样子如果两行的 x 值相同(看起来不错):
How it should look
这是它的实际外观 curveBasis如果两行的 x 值不同(看起来不太好):
How it currently looks (not good)
当前代码/策略
这是当前的策略(请注意,我将线条称为好/坏,其中顶部的好线导致绿色填充,顶部的坏线导致红色填充)(删除了一些内容,例如类名等以减少困惑) :

// I also set the domain and range appropriately for x/y--not shown here:
const x = d3.scaleTime();
const y = d3.scaleLinear();

// 1. Draw the lines "normally" (this is in a loop to build each line)
const lineData = d3.line()
.defined(point => !isNaN(point.y))
.x(point => x(point.x))
.y(point => y(point.y))
.curve(d3[lineCurve]);

d3Chart.append('path')
.datum(points)
.attr('d', lineData);

// 2. "Normalize" lines into the following format for each point (logic not shown here): {x, goodY, badY}
// Bind this data to a new svg group
const areaElement = d3Chart.append('g').datum(normlaizedData);

// 3. Clip paths and area paths

// Create the green fill clip path.
const goodLineClipPathId = `good-line-clip-path`;
areaElement.append('clipPath')
.attr('id', goodLineClipPathId)
.append('path')
.attr('d', d3.area()
.curve(lineCurve)
.x(point => x(point.x))
.y0(0)
.y1(point => y(point.badY))
);

// Create the red fill clip path.
const badLineClipPathId = `bad-line-clip-path`;
areaElement.append('clipPath')
.attr('id', badLineClipPathId)
.append('path')
.attr('d', d3.area()
.curve(lineCurve)
.x(point => x(point.x))
.y0(height)
.y1(point => y(point.badY))
);

// Create the red fill.
areaElement.append('path')
.attr('clip-path', `url(#${badLineClipPathId})`)
.attr('d', d3.area()
.curve(lineCurve)
.x(point => x(point.x))
.y0(point => y(point.goodY))
.y1(point => y(point.badY))
);

// Create the green fill.
areaElement.append('path')
.attr('clip-path', `url(#${goodLineClipPathId})`)
.attr('d', d3.area()
.curve(lineCurve)
.x(point => x(point.x))
.y0(point => y(point.badY))
.y1(point => y(point.goodY))
);
考虑的解决方案
我的一个想法是“克隆”确切的 svg 行,但切掉开头/结尾(使行的其余部分保持不变)并将这些行用作区域的顶部/底部(并用直线垂直关闭末端行);但是路径数据本身利用了曲线,所以改变开始/结束仍然会影响线(除非有办法解决这个问题)。
这是我想到的另一个想法:不要“标准化”线条并创建额外的剪辑以“切断”末端(在屏幕截图上绘制的垂直黑线处);但即使我这样做了,仍然会有问题(如箭头所示)。
Possible solution--still has problems

最佳答案

这不是一个很好的解决方案 ,但我发帖是因为它是一种解决方案(或至少是部分解决方案)。
在没有详细介绍的情况下,我注意到问题实际上有两个可能的原因(一个或两个都可能导致间隙或流血):

  • 这些行不会以相同的 x 值开始和/或结束。
  • 这些行不共享 x 值与实际 y 值的 1 到 1 映射(换句话说,两行中至少有一行“缺少”另一行中未丢失的相应 x 值的 y 值) .

  • 《解决方案》
    注意:我只用 curveBasis 测试过这个-- 其他弯曲类型的工作方式可能不同。
  • “填充”缺失的 y 值(修复上面的原因#2)--我通过在最近的左/右非缺失点之间进行线性插值来做到这一点(如果缺失值位于行的末尾或开头,则最近的非缺失点) - 重新使用了缺失的点值)。在您的规范化和原始行中执行此操作,但不要在原始行中的点和不在规范化行中的点之间进行插值 - 在这种情况下只需重新使用(请参见下面的示例)。
  • “三次重复”规范化的起点/终点(修复上面的第 1 个原因)——我通过在规范化数据开始和线数据结束的 x 值处从字面上克隆同一点两次来做到这一点。只需要在您的原始(非规范化)行中执行此操作——规范化行已经在它们需要的地方开始/结束。这适用于 curveBasis ,因为曲线考虑了哪些点 - 该解决方案本质上强制一种线“结束”,即使它位于线的中间( source for documentation quote below ):

  • [curveBasis] Produces a cubic basis spline using the specified control points. The first and last points are triplicated such that the spline starts at the first point and ends at the last point...


    示例
    第 1 行(x 值): [3, 4, 5, 7, 8, 9, 10, 11]原来的 [3, 4, 5, 6 (null y), 7, 8, 9, 10, 11]规范化,预操作 [3, 4, 5, 6 (interpolated y), 7, 8, 9, 10, 11]标准化,后处理 [3, 3, 3, 4, 5, 6 (interpolated y), 7, 8, 9, 10, 11, 11, 11]原创,后期处理
    请注意,对于第 1 行,我们可以跳过将起点/终点重复三次,因为它们已经是原始线的起点/终点
    第 2 行(x 值): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13]原来的 [3, 4, 5, 6, 7, 8, 9, 10, 11 (null y)]规范化,预操作 [3, 4, 5, 6, 7, 8, 9, 10, 11 (re-used y from 10)]标准化,后处理 [1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11 (re-used y from 10), 11 (re-used y from 10), 11 (re-used y from 10), 13]原始,后处理(请注意,我们不会在 10 和 13 之间进行插值以获得 11,因为标准化行中不存在 13)
    它是什么样子的?
    不是那么好 - 但是,嘿,没有间隙或流血!箭头指向我们“重复三次”点以强制曲线在那里“结束”的地方。
    enter image description here
    我们要使用这个吗?
    不见得。我仍在寻找更好的解决方案;但这是我到目前为止想出的。

    关于d3.js - 如何在 d3 中在两条不同长度(不同 x 值)的曲线之间绘制区域/填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63402624/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com