javascript - 三次线图无法正确绘制?

标签 javascript math d3.js

我这里有一个三次线图:https://jsfiddle.net/v6bLu80w/2/ ,它应该始终绘制一条穿过所示三个点的线。其上方的 slider 增强了方程,同时将其保持在点内。或者至少,应该如此,这让我想到了我的问题。

在我的图表中,我使用以下方程来设置三次方的系数:

xzero = (thirdy - (firsty * Math.pow(thirdx, 3) / Math.pow(firstx, 3)) + (secondy * Math.pow(thirdx, 3) / firstx) - (Math.pow(thirdx, 3) * (firsty * Math.pow(secondx, 3) / Math.pow(firstx, 3)) / firstx) + (Math.pow(thirdx, 3) * (xone * (secondx, 3) / Math.pow(xone, 2)) / firstx) + (xone * Math.pow(thirdx, 3) / Math.pow(firstx, 2)) - secondy * Math.pow(thirdx, 2) + (firsty * Math.pow(secondx, 3) * Math.pow(thirdx, 2) / Math.pow(firstx, 3)) - (xone * Math.pow(secondx, 3) * Math.pow(thirdx, 2) / Math.pow(firstx, 2)) + (xone * secondx * Math.pow(thirdx, 2)) - xone * thirdx) / (1 + (Math.pow(secondx, 3) * Math.pow(thirdx, 2) / Math.pow(firstx, 3)) + (Math.pow(thirdx, 3) / firstx) - Math.pow(thirdx, 2) - (Math.pow(secondx, 3) * Math.pow(thirdx, 3) * (1 / Math.pow(firstx, 3)) / firstx))

xtwo = (secondy - (firsty * Math.pow(secondx, 3) / Math.pow(firstx, 3)) + (xone * Math.pow(secondx, 3) / Math.pow(firstx, 2)) + (xzero * Math.pow(secondx, 3) / Math.pow(firstx, 3)) - xone * secondx - xzero) / (Math.pow(secondx, 2) - (Math.pow(secondx, 3) / firstx));
xthree = (firsty / Math.pow(firstx, 3)) - (xtwo / firstx) - (xone / Math.pow(firstx, 2)) - (xzero / Math.pow(firstx, 3));

根据我使用的代数,所有方程都应该经过这三个点,但从程序中可以看出,对于除起始值之外的所有 slider 值,该线都会移出第三个点。

我想知道为什么它没有经历第三点,以及针对这种情况的任何解决方案(如果可能的话)。

我仍然无法找出问题所在,因此我们将不胜感激。

最佳答案

在您的代码中,您有以下语句(分为几行):

xzero = (
    thirdy 
    - (firsty * Math.pow(thirdx, 3) / Math.pow(firstx, 3)) 
    + (secondy * Math.pow(thirdx, 3) / firstx) 
    - (Math.pow(thirdx, 3) * (firsty * Math.pow(secondx, 3) / Math.pow(firstx, 3)) / firstx) 
    + (Math.pow(thirdx, 3) * (xone * (secondx, 3) / Math.pow(xone, 2)) / firstx) 
    + (xone * Math.pow(thirdx, 3) / Math.pow(firstx, 2)) 
    - secondy * Math.pow(thirdx, 2) 
    + (firsty * Math.pow(secondx, 3) * Math.pow(thirdx, 2) / Math.pow(firstx, 3)) 
    - (xone * Math.pow(secondx, 3) * Math.pow(thirdx, 2) / Math.pow(firstx, 2)) 
    + (xone * secondx * Math.pow(thirdx, 2)) 
    - xone * thirdx
) / (
    1 
    + (Math.pow(secondx, 3) * Math.pow(thirdx, 2) / Math.pow(firstx, 3)) 
    + (Math.pow(thirdx, 3) / firstx) 
    - Math.pow(thirdx, 2) 
    - (Math.pow(secondx, 3) * Math.pow(thirdx, 3) * (1 / Math.pow(firstx, 3)) / firstx )
)

这里有一些问题。到目前为止,最大的一个问题是,这是一个非常长的语句,它在一个地方放置了太多的内容,并且在构建时很容易犯错误,因为人类实际上非常不擅长跟踪括号。至少找一个带有括号突出显示的编辑器,这样您就会收到提醒,尽早知道要关闭哪个括号。

像这样的语句会因为以下几个原因而出错:

  1. 您忘记了括号。第一次尝试格式化时,我认为末尾有一个额外的右括号。哪个学期应该结束?实际上是否缺少一个开括号?我的括号格式是否错误?
  2. 因为它没有被分割成更小的部分,所以很难选出一个中间值并看看它是否符合您的期望,即测试示例。要么全部有效,要么全部无效,这就是你当前的问题。
  3. 无法阅读。这是只写代码,需要仔细研究才能理解。仅仅格式化这些行就花了几分钟。它与所有括号的绝对质量违背了你的大脑在任何级别上发现错误的能力,例如你有 xone * (secondx, 3) 的部分,这似乎会导致 xone * 3 在我的控制台中,但似乎不太正确。

我怀疑它似乎仍然适用于前 2 点的原因是,计算出 xzero 系数后,您可以使用前两点(但不是第三点)的坐标来获取其他系数。这将根据您的 xzero 公式构建一条通过这两个点和另一个点的曲线,从而形成您所看到的行为。

一般来说,很难以合理的方式将数学公式转化为代码。并非不可能,但值得为之努力。通常,在每个系数或因子的计算之上添加伪数学注释可以更容易地首先编写正确的代码,更不用说稍后修复错误了。

如果您有一个函数来求解一组特定的值并返回答案(而不是直接更新全局变量),那么您可以通过调用该函数并检查返回值来为特定情况编写单元测试。对于一些非常基本的情况(y = 常数、y = x、y = -x^2)这样做将快速指示误差源,因为系数的值显然是正确或错误的。像这样的代码需要从简单到复杂进行构建。我曾经认为,如果我能潜入顶部并获得正确的数字代码,我就很聪明。现在我认识到自己的愚蠢了。

关于上述语句中执行的求解;由于您正在求解 3 个系数(给出了 xone)并给出了 3 个 x,y 对,因此完全可以进行 3 阶矩阵求逆来获得系数。为此,有可用的代码示例、库等。将其重新表述为矩阵求逆还可以解锁围绕此类求逆的数学,特别是答案未知的输入组合 - 例如,分母项为零,或者 firstx 为零且分子和分母都为零是无限的...换句话说,利用已经完成的大量工作来使您的解决方案真正变得非常好。

关于javascript - 三次线图无法正确绘制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32012958/

相关文章:

javascript - 在 HTML5 Web App 中使用 OAuth2

algorithm - 球桶,如果我添加另一个球,一个桶会装满吗?

javascript - 如何同时使用 Express 和 & 符号?

javascript - 如何使用 d3 重新启动(恢复) Canvas 动画中暂停的计时器

javascript - webpack 循环导入返回空对象

javascript - 具有语义 ui 的动画

javascript - Angular:如何在 Angular 5 中实现类似 ng-include 的功能?

python - 你能对 Django 查询集中的聚合值做额外的数学运算吗

c++ - 从测量值创建反向查找表

d3.js - 缩放时 Datamaps D3 Pin/marker 常量大小和相对位置的问题