Easing functions¶
By default, all animations are rendered with a linear time progression. If your video has multiple steps, the transition between them will appear abrupt as you end one and start another. This can be fixed by using easing functions. Easing functions are mappings between frame number and a time parameter. For example, you might want to start your animations slowly, and end very fast; in this case you’d want to use a non-linear easing function.
There are multiple ways to use an easing function in diplotocus. You can either set an easing for a whole timeline, a plot object, a seq.animate() function or an animation function. If multiple easings are set, the priority goes from the more specific to the more general, i.e. the easing is selected in this order :
an easing set on the animation function, or if not set :
an easing set on the seq.animate() function, or if not set :
an easing set on the plot object, or if not set :
an easing set on the timeline, or if not set :
no easing (i.e.
dpl.easeLinear()).
Here are all the easing functions implemented in diplotocus:
easeLinear¶
f(x) = x
Sine¶
easeInSine:¶
f(x) = 1 - cos((x * π) / 2)
easeOutSine():¶
f(x) = sin((x * π) / 2)
easeInOutSine():¶
f(x) = -(cos(π * x) - 1) / 2
Quadratic¶
easeInQuad():¶
f(x) = x^2
easeOutQuad():¶
f(x) = 1 - (1 - x) * (1 - x)
easeInOutQuad():¶
f(x) = x < 0.5 ? 2 * x^2 : 1 - (-2 * x + 2)^2 / 2
Cubic¶
easeInCubic():¶
f(x) = x^3
easeOutCubic():¶
f(x) = 1 - (1 - x)^3
easeInOutCubic():¶
f(x) = x < 0.5 ? 4 * x^3 : 1 - (-2 * x + 2)^3 / 2
Quartic¶
easeInQuart():¶
f(x) = x^4
easeOutQuart():¶
f(x) = 1 - (1 - x)^4
easeInOutQuart():¶
f(x) = x < 0.5 ? 8 * x^4 : 1 - (-2 * x + 2)^4 / 2
Quintic¶
easeInQuint():¶
f(x) = x^5
easeOutQuint():¶
f(x) = 1 - (1 - x)^5
easeInOutQuint():¶
f(x) = x < 0.5 ? 16 * x^5 : 1 - (-2 * x + 2)^5 / 2
Exponential¶
easeInExpo():¶
f(x) = x === 0 ? 0 : 2^(10 * x - 10)
easeOutExpo():¶
f(x) = x === 1 ? 1 : 1 - 2^(-10 * x)
easeInOutExpo():¶
f(x) = x === 0
? 0
: x === 1
? 1
: x < 0.5 ? Math.pow(2, 20 * x - 10) / 2
: (2 - Math.pow(2, -20 * x + 10)) / 2
Circular¶
easeInCirc():¶
f(x) = 1 - sqrt(1 - x^2)
easeOutCirc():¶
f(x) = sqrt(1 - (x - 1)^2)
easeInOutCirc():¶
f(x) = x < 0.5
? (1 - sqrt(1 - (2 * x)^2)) / 2
: (sqrt(1 - (-2 * x + 2)^2) + 1) / 2
Back¶
easeInBack():¶
c1 = 1.70158
c3 = c1 + 1
f(x) = c3 * x * x * x - c1 * x * x
easeOutBack():¶
c1 = 1.70158
c3 = c1 + 1
f(x) = 1 + c3 * (x - 1)^3 + c1 * (x - 1)^2
easeInOutBack():¶
c1 = 1.70158
c2 = c1 * 1.525
f(x) = x < 0.5
? ((2 * x)^2 * ((c2 + 1) * 2 * x - c2)) / 2
: ((2 * x - 2)^2 * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2
Elastic¶
easeInElastic():¶
c4 = (2 * π) / 3
f(x) = x === 0
? 0
: x === 1
? 1
: -2^(10 * x - 10) * sin((x * 10 - 10.75) * c4)
easeOutElastic():¶
c4 = (2 * π) / 3
f(x) = x === 0
? 0
: x === 1
? 1
: 2^(-10 * x) * sin((x * 10 - 0.75) * c4) + 1
easeInOutElastic():¶
c4 = c5 = (2 * π) / 4.5
f(x) = x === 0
? 0
: x === 1
? 1
: x < 0.5
? -(2^(20 * x - 10) * sin((20 * x - 11.125) * c5)) / 2
: (2^(-20 * x + 10) * sin((20 * x - 11.125) * c5)) / 2 + 1
Bounce¶
easeInBounce():¶
f(x) = 1 - f_easeOutBounce(1 - x)
easeOutBounce():¶
n1 = 7.5625
d1 = 2.75
if (x < 1 / d1) {
f(x) = n1 * x * x
} else if (x < 2 / d1) {
f(x) = n1 * (x -= 1.5 / d1) * x + 0.75
} else if (x < 2.5 / d1) {
f(x) = n1 * (x -= 2.25 / d1) * x + 0.9375
} else {
f(x) = n1 * (x -= 2.625 / d1) * x + 0.984375
}
easeInOutBounce():¶
f(x) = 1 - f_easeOutBounce(1 - x)
f(x) = x < 0.5
? (1 - f_easeOutBounce(1 - 2 * x)) / 2
: (1 + f_easeOutBounce(2 * x - 1)) / 2
easeCubicBezier(x1,y1,x2,y2)¶
This function lets you define a custom easing function, as a cubic Bézier curve. The implementation is similar to the CSS one, i.e. it is inverting the x(t)=t relation to find a y(t) solution, given the positions of the control points P1=(x1,y1) and P2=(x2,y2).
Note
You can use cubic-bezier.com to find the right easing for you.
ease = dpl.easings.easeCubicBezier(.43,-0.5,.56,1.5)
x = np.linspace(0,1,200)
y = [ease.ease(el) for el in x]
ease_str = 'Cubic Bézier'
lims = (-0.1,1.1)
tl = dpl.Timeline(quiet=True,figsize=(6,5),xlim=lims,ylim=lims,noaxis=True)
ax = tl.main_axis
ax.plot(x,y,alpha=0.5)
ax.text(0.1,0.8,ease_str)
ax.text(0.1,0.3,'Linear',alpha=0.5)
e = dpl.plot(x=0,y=0.75,c='k',marker='o',markersize=10,easing=ease)
l = dpl.plot(x=0,y=0.25,c='k',marker='o',markersize=10,alpha=0.5)
p = dpl.plot(x=x,y=y,c='C0')
e.translate((0,0),(1,0),200)
l.translate((0,0),(1,0),200)
p.draw(200)
tl.animate((e,l,p))
tl.wait(25)
tl.save_video(path='../_static/cubicBezier.mp4',speed=4)
custom easing function¶
For more complicated easing functions than cubic Bézier curves, you can define your own by creating a child class of the diplotocus.easings.Easing class. All you have to do is define its ease(self,x) method so it returns a time parameter for a given linear time x. Here’s an example:
class myEase(dpl.easings.Easing):
def ease(self,x):
if x < 0.75:
return np.abs(np.sin(x*4/.75*np.pi))/(x*5+1)
else:
return ((x-.75)/.25)**2