-
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
d3.interpolateFunction? #29
Comments
Are you imagining something like d3.interpolateMeta(a, b) that takes two interpolators and returns an interpolator that linearly interpolates the output of a and b? |
Maybe. I was looking at my hand-crafted function and thinking about how I would generalize it to allow the functions themselves to be interpolators (and so, to allow things to gel with non-number output types.) I think it works cleanly? (i.e. without excessive object creation) But if not, I would be happy with a function that only to interpolated between unary functions from reals to reals. |
Right, so here's a general, but possibly unperformant implementation:
Here we do the interpolation in the domain, since we don't want to assume the codomain is numeric. This leads directly calling the (possibly expensive?) factory on each step. If we know the codomain is numeric, we can do the interpolation there instead. Note this won't in general result in the same interpolator as above, but that's ok: I just want a continuous, linearish deformation.
|
Err, excuse me. My
Here |
Sorry, last one. Upon third reading, my |
I was thinking this: function interpolateMeta(a, b) {
return (t) => interpolate(a(t), b(t))(t);
} Which, as you point out, isn’t ideal from a performance perspective because it creates as new closure for each invocation of the meta-interpolator. This is an unfortunate consequence of the design of interpolators in this library. But, since the behavior of d3.interpolate is explicitly defined, it could use private internal methods to implement the above behavior more efficiently, after restructuring the implementation of the other interpolators, e.g., // A private function that interpolates directly rather than returning an interpolator.
function interpolateNumber(a, b, t) {
return (a = +a) + (b - a) * t;
} A more extreme option would be to have separate methods, i.e., to make the above reusable implementation public:
That might be a good long-term strategy although it’s highly inconvenient in terms of backwards-compatibility. Technically, it doesn’t require that the domains of the two interpolators a and b are the unit interval—that’s just the convention. But it does require that they have the same domain, and that this domain is also the domain that will be used with the returned “meta” interpolator. |
Oh also, as far as the dynamically-typed nature of d3.interpolate goes, the behavior of d3.interpolateMeta could be defined such that the first time the returned interpolator is invoked, it determines the type of interpolator to use subsequently based on the return value of b(t). So if b(t) is a string, then it henceforth uses d3.interpolateString every time (even if subsequently the behavior of b changes—though in practice it’s hard to imagine a good reason for an interpolator to return inconsistent types). |
Lastly if you could elaborate on some practical use cases for this feature it would be helpful in establishing motivation. Thanks! |
The motivation is visually intuitive non-linear transforms of unit square patches (linear transforms are already easy directly with SVG.) The unit square restriction may look odd, but it makes what comes next easier. Such patches are also easy to make from arbitrary rectangles using the existing So as an example, imagine transforming a time-series line graph (given by function I think one answer is:
For our given Let's see if we can tease the bits apart a little.
Make sure I'm not nuts:
I get the feeling we can play with binder order to avoid making closures, but I need to run for the moment. |
I have a need to linearly deform one (unary, real domain) function onto another.
As a new d3 user I'm still learning what's in the kitchen, so to speak. Before discovering
d3-interpolate
I was cobbling this feature together withd3.scaleLinear
. However this was falling down due to needing to construct such a scale on each interpolator call.Doing the interpolation explicitly fixed the issue and is easy enough, but it felt a little counter to the intended style. After noticing
d3-interpolate
I hoped I would find such a function interpolator (homotopy) constructor, but no dice.Could it be added?
The text was updated successfully, but these errors were encountered: