-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New interpolateFromCurve, interpolateCardinal, interpolateCatmull-Rom & interpolateMonotoneX #67
Conversation
Here is the original function on observable: https://observablehq.com/@andreasplesch/svg-path-sampler It can be imported into other notebooks, for example: https://observablehq.com/@andreasplesch/line-chart Here is a discussion: https://talk.observablehq.com/t/obtain-interpolated-y-values-without-drawing-a-line/1796 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it is not a the lightest solution but it is often requested since d3 users see the curves and think there must an interpolator as well. It feels, it should go in a helper/addon repo but I do not know if there is such a thing.
src/fromCurve.js
Outdated
l = (mn + l) / 2; | ||
} | ||
nextDelta = svgpath.getPointAtLength(l).x - targetX; | ||
if (Math.abs(Math.abs(delta) - Math.abs(nextDelta)) < epsilon) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was an attempt to detect lack of improvement during iteration and then bailing. But it turned out to be a flawed idea since there may be no improvement in the current bisecting but there could be still improvement in the next one. I think it is better to remove that check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @andreasplesch I will make these tweaks.
And thanks for coming up with this ideas in the first place! All credit goes to you for this!
Thanks for the pull request. I recommend you release this as a standalone module. I tend to keep the core modules small. |
Thanks for reviewing Mike, I will indeed consider releasing this as a standalone module. But before I do I’d be interested to know you have seen much appetite for a potential I am happy to close this PR and go for separate module, but would like to make one last bid for consideration for it to go into core as I think this would benefit other non-SVG based applications. Thanks for all you great work Mike! |
I have not heard any other requests for this feature. Also, I would suggest parametric evaluation of curves rather than using SVG’s getPointAtLength, as shown here for cubic Bézier segments: https://observablehq.com/@mbostock/fourier-series-path-sampling |
Requests for interpolators corresponding to the curves do come up regularly, Here is one: #52 . It is a natural expectation. |
Thanks @mbostock I have opted to create this as a standalone module https://github.com/jamesleesaunders/d3-interpolate-curve should you ever want to include this in core I would be more than happy to help. @andreasplesch I hope you don't mind me taking the reins on this one. I have added you as a collaborator to d3-interpolate-curve please feel free to contribute as you see fit. |
I don’t think you would need any bisection or search at all—just direct evaluation. See interpolateBasis for example: the total curve is divided into n segments, which are then evaluated using the basis function. https://github.com/d3/d3-interpolate/blob/master/src/basis.js |
Yes, but only if you want the x and y of a given t, no ? Often what is needed is the y of an x. |
Correct, yes. In the case of interpolateBasis it’s simply f(t) outputs a number in [0, n] that is then passed to a piecewise linear interpolator. In the general case of a two-dimensional curve in xy there could be more than one y-value for a given x. |
True, the general case needs the parametric form. The case of a single-valued function (http://mathworld.wolfram.com/Function.html) is the common case and is often expected to be evaluated as y(x). And people then just use the curves to fit something and want to access it as y(x). |
Although D3 has a wide selection of curve functions; curveMonotoneX, curveCardinal etc. for generating SVG curves, there is not as many interpolate functions for situations where, rather than SVG, we want to interpolate values for other use, for example in my case X3DOM IndexedFaceSet.
This PR adds 4 new interpolation functions which compliment the existing intrpolateBasis function:
d3.interpolateFromCurve(values, d3.curveMonotoneX);
These have been developed with the help from a fellow X3DOM developer @andreasplesch who came up with the the original draft version of interpolateFromCurve.
To see a demo of these in action see:
https://observablehq.com/@jamesleesaunders/why-are-there-no-d3-interpolatecardinal-and-d3-interpolate
The problem with this function is considerably inefficient because, under the hood, it has to create a detached SVG element, generate the curve then reverse engineer the SVG curve back to values. The process of converting values -> curve -> svg -> values is a little bit long winded and could be a little heavy.