-
-
Notifications
You must be signed in to change notification settings - Fork 544
[WIP] Animation documentation #527
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
_posts/plotly_js/animations/2016-08-29-animations_plotly_js_index.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--- | ||
title: JavaScript Graphing Library Animations | Examples | Plotly | ||
name: Animations | ||
permalink: javascript/animations/ | ||
description: How to animate charts in JavaScript with the animate API. | ||
layout: base | ||
thumbnail: thumbnail/animations.gif | ||
language: plotly_js | ||
page_type: example_index | ||
has_thumbnail: true | ||
display_as: chart_events | ||
order: 0.5 | ||
--- | ||
{% assign examples = site.posts | where:"language","plotly_js" | where:"suite","animations" | sort: "order" %} | ||
{% include auto_examples.html examples=examples %} |
72 changes: 72 additions & 0 deletions
72
_posts/plotly_js/animations/2016-09-15-animations-animating-many-frames-quickly.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
--- | ||
name: Animating Many Frames Quickly | ||
plot_url: http://codepen.io/plotly/embed/NRNJpv/?height=500&theme-id=15263&default-tab=result | ||
language: plotly_js | ||
suite: animations | ||
order: 5 | ||
sitemap: false | ||
arrangement: horizontal | ||
markdown_content: | | ||
By default and to ensure any properties that cannot be animated are applied to the plot, a full redraw occurs after each transition. This is generally desirable, but hurts performance when you wish to animate frames as quickly as possible. The example below performs a live simulation of the Lorenz attractor and greatly improves the performance by eliminating the redraw with `redraw: false`. | ||
--- | ||
var n = 100; | ||
var x = [], y = [], z = []; | ||
var dt = 0.015; | ||
|
||
for (i = 0; i < n; i++) { | ||
x[i] = Math.random() * 2 - 1; | ||
y[i] = Math.random() * 2 - 1; | ||
z[i] = 30 + Math.random() * 10; | ||
} | ||
|
||
Plotly.plot('graph', [{ | ||
x: x, | ||
y: z, | ||
mode: 'markers' | ||
}], { | ||
xaxis: {range: [-40, 40]}, | ||
yaxis: {range: [0, 60]} | ||
}) | ||
|
||
function compute () { | ||
var s = 10, b = 8/3, r = 28; | ||
var dx, dy, dz; | ||
var xh, yh, zh; | ||
for (var i = 0; i < n; i++) { | ||
dx = s * (y[i] - x[i]); | ||
dy = x[i] * (r - z[i]) - y[i]; | ||
dz = x[i] * y[i] - b * z[i]; | ||
|
||
xh = x[i] + dx * dt * 0.5; | ||
yh = y[i] + dy * dt * 0.5; | ||
zh = z[i] + dz * dt * 0.5; | ||
|
||
dx = s * (yh - xh); | ||
dy = xh * (r - zh) - yh; | ||
dz = xh * yh - b * zh; | ||
|
||
x[i] += dx * dt; | ||
y[i] += dy * dt; | ||
z[i] += dz * dt; | ||
} | ||
} | ||
|
||
function update () { | ||
compute(); | ||
|
||
Plotly.animate('graph', { | ||
data: [{x: x, y: z}] | ||
}, { | ||
transition: { | ||
duration: 0 | ||
}, | ||
frame: { | ||
duration: 0, | ||
redraw: false | ||
} | ||
}); | ||
|
||
requestAnimationFrame(update); | ||
} | ||
|
||
requestAnimationFrame(update); |
44 changes: 44 additions & 0 deletions
44
_posts/plotly_js/animations/2016-09-15-animations-animating-sequences-of-frames.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
--- | ||
name: Animating Sequences of Frames | ||
plot_url: http://codepen.io/plotly/embed/qakvRz/?height=500&theme-id=15263&default-tab=result | ||
language: plotly_js | ||
suite: animations | ||
order: 4 | ||
sitemap: false | ||
arrangement: horizontal | ||
markdown_content: | | ||
The above examples have used one frame at a time. Whether passing objects as frames or referring to frames by name, you may pass multiple frames together in an array. If `null` or `undefined` is passed as the second argument (i.e. `Plotly.animate('graph')`), then all defined frames will be animated in sequence. | ||
|
||
The third argument of `Plotly.animate` contains animation options. The transition duration defines the amount of time spent interpolating a trace from one state to another (currently limited to scatter traces), while the frame duration defines the total time spent in that state, including time spent transitioning. The example below has two frames, each with their own transition and frame timing. | ||
--- | ||
Plotly.plot('graph', [{ | ||
x: [0, 0], | ||
y: [-1, 1], | ||
}], { | ||
xaxis: {range: [-Math.PI, Math.PI]}, | ||
yaxis: {range: [-1.3, 1.3]} | ||
}).then(function () { | ||
Plotly.addFrames('graph', [ | ||
{ | ||
data: [{x: [1, -1], y: [0, 0]}], | ||
name: 'frame1' | ||
}, { | ||
data: [{x: [0, 0], y: [-1, 1]}], | ||
name: 'frame2' | ||
} | ||
]); | ||
}) | ||
|
||
function startAnimation() { | ||
Plotly.animate('graph', ['frame1', 'frame2'], { | ||
frame: [ | ||
{duration: 1500}, | ||
{duration: 500}, | ||
], | ||
transition: [ | ||
{duration: 800, easing: 'elastic-in'}, | ||
{duration: 100, easing: 'cubic-in'}, | ||
], | ||
mode: 'afterall' | ||
}) | ||
} |
31 changes: 31 additions & 0 deletions
31
_posts/plotly_js/animations/2016-09-15-animations-animating-the-data.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
--- | ||
name: Animating the Data | ||
plot_url: http://codepen.io/plotly/embed/ZpWPpj/?height=500&theme-id=15263&default-tab=result | ||
language: plotly_js | ||
suite: animations | ||
order: 1 | ||
sitemap: false | ||
arrangement: horizontal | ||
markdown_content: | | ||
The animate command lets you add dynamic behavior to Plotly graphs in a number of different ways. At its core, `Plotly.animate` transitions traces to a new state or sequence of states. When you tell Plotly to animate, it merges the properties you've supply into the current state of the plot. Therefore to animate a trace, *you must first plot the trace you wish to animate*. | ||
|
||
The example below transitions to new y-values each time the button is pressed. Note that to prevent artifacts while animating, the default line simplification algorithm is explicitly disabled. Currently, only scatter traces may be smoothly transitioned from one state to the next. Other traces are compatible with frames and animations but will be updated instantaneously. | ||
--- | ||
Plotly.plot('graph', [{ | ||
x: [1, 2, 3], | ||
y: [0, 0.5, 1], | ||
line: {simplify: false}, | ||
}]); | ||
|
||
function randomize() { | ||
Plotly.animate('graph', { | ||
data: [{y: [Math.random(), Math.random(), Math.random()]}], | ||
traces: [0], | ||
layout: {} | ||
}, { | ||
transition: { | ||
duration: 500, | ||
ease: 'cubic-in-out' | ||
} | ||
}) | ||
} |
42 changes: 42 additions & 0 deletions
42
_posts/plotly_js/animations/2016-09-15-animations-animating-the-layout.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
--- | ||
name: Animating the Layout | ||
plot_url: http://codepen.io/plotly/embed/GjkZNk/?height=500&theme-id=15263&default-tab=result | ||
language: plotly_js | ||
suite: animations | ||
order: 2 | ||
sitemap: false | ||
arrangement: horizontal | ||
markdown_content: | | ||
The example below transitions to a new axis range each time the button is pressed. A present limitation of the animate API is that only one of either data or layout may be smoothly transitioned at a time. If both are provided, the data will be updated instantaneously after the layout is transitioned. | ||
--- | ||
var n = 500; | ||
var x = [], y = []; | ||
for (var i = 0; i < n; i++) { | ||
x[i] = i / (n - 1); | ||
y[i] = x[i] + 0.2 * (Math.random() - 0.5); | ||
} | ||
|
||
Plotly.plot('graph', [{ | ||
x: x, | ||
y: y, | ||
mode: 'markers' | ||
}], { | ||
xaxis: {range: [0, 1]}, | ||
yaxis: {range: [0, 1]} | ||
}); | ||
|
||
function zoom() { | ||
var min = 0.45 * Math.random(); | ||
var max = 0.55 + 0.45 * Math.random(); | ||
Plotly.animate('graph', { | ||
layout: { | ||
xaxis: {range: [min, max]}, | ||
yaxis: {range: [min, max]} | ||
} | ||
}, { | ||
transition: { | ||
duration: 500, | ||
easing: 'cubic-in-out' | ||
} | ||
}) | ||
} |
55 changes: 55 additions & 0 deletions
55
_posts/plotly_js/animations/2016-09-15-animations-defining-named-frames.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
--- | ||
name: Defining Named Frames with <code>Plotly.addFrames</code> | ||
plot_url: http://codepen.io/plotly/embed/wzGOgd/?height=500&theme-id=15263&default-tab=result | ||
language: plotly_js | ||
suite: animations | ||
order: 3 | ||
sitemap: false | ||
arrangement: horizontal | ||
markdown_content: | | ||
The above examples pass the data itself through the <code>Plotly.animate</code> command. You may instead predefine named frames through the <code>Plotly.addFrames</code> command. Then, instead of passing frames through `Plotly.animate`, you may simply refer to a frame by name. | ||
|
||
Similar to traces, frames are assigned a serial index as they are added. Frames may be updated by passing an array of frame indices. For example, the command to update the frame with index 2 would be `Plotly.addFrames('graph', [{...}], [2])`. Frames can be similarly deleted with, for example, `Plotly.deleteFrames('graph', [2])`. | ||
|
||
The following example uses frames together with an `updatemenu` for interactive transitions. | ||
--- | ||
var frames = [ | ||
{name: 'sine', data: [{x: [], y: []}]}, | ||
{name: 'cosine', data: [{x: [], y: []}]}, | ||
{name: 'circle', data: [{x: [], y: []}]}, | ||
]; | ||
|
||
var n = 100; | ||
for (var i = 0; i < n; i++) { | ||
var t = i / (n - 1) * 2 - 1; | ||
|
||
// A sine wave: | ||
frames[0].data[0].x[i] = t * Math.PI; | ||
frames[0].data[0].y[i] = Math.sin(t * Math.PI); | ||
|
||
// A cosine wave: | ||
frames[1].data[0].x[i] = t * Math.PI; | ||
frames[1].data[0].y[i] = Math.cos(t * Math.PI); | ||
|
||
// A circle: | ||
frames[2].data[0].x[i] = Math.sin(t * Math.PI); | ||
frames[2].data[0].y[i] = Math.cos(t * Math.PI); | ||
} | ||
|
||
Plotly.plot('graph', [{ | ||
x: frames[0].data[0].x, | ||
y: frames[0].data[0].y, | ||
line: {simplify: false}, | ||
}], { | ||
xaxis: {range: [-Math.PI, Math.PI]}, | ||
yaxis: {range: [-1.2, 1.2]}, | ||
updatemenus: [{ | ||
buttons: [ | ||
{method: 'animate', args: [['sine']], label: 'sine'}, | ||
{method: 'animate', args: [['cosine']], label: 'cosine'}, | ||
{method: 'animate', args: [['circle']], label: 'circle'} | ||
] | ||
}] | ||
}).then(function() { | ||
Plotly.addFrames('graph', frames); | ||
}); |
94 changes: 94 additions & 0 deletions
94
_posts/plotly_js/animations/2016-09-15-animations-frame-groups-and-animation-modes.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
--- | ||
name: Frame Groups and Animation Modes | ||
plot_url: http://codepen.io/plotly/embed/rrZRmA/?height=500&theme-id=15263&default-tab=result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👏 👏 I love this example so much-- this is one of the coolest thing I've ever seen plotly do!!!!!!!!!!!!! |
||
language: plotly_js | ||
suite: animations | ||
order: 7 | ||
sitemap: false | ||
arrangement: horizontal | ||
markdown_content: | | ||
The following example combines many of these concepts to draw a glass filling with water. | ||
|
||
The first row of buttons animates a different set of predefined frames by changing the second argument of `Plotly.animate`. Passing `null` or `undefined` animates all defined frames in sequence, while passing an array of strings (here, the frames in reverse) animates a specific sequence of frames. By passing a plain string (here, `lower` or `upper`), it filters the animated frames to those with a `group` property equal to that name. The stop button is accomplished by interrupting the current animation with an empty list of frames, therefore simply stopping the animation at the end of the current frame. | ||
|
||
The second row of buttons animates all frames with different animation modes. The `mode` option defines whether an animation either interrupts or follows the current animation. `immediate` mode discards all queued frames and begins a new sequence immediately. The `next` mode is very similar but doesn't begin the new animation until the *end* of the current frame. Finally, `afterall` queues the new frames so that the new animation begins only after all previous animations have completed. | ||
--- | ||
var i, j, t, x, y, name; | ||
var frames = []; | ||
var nFrames = 10; | ||
var n = 80; | ||
var reverseFrames = []; | ||
|
||
for (i = 0; i < nFrames; i++) { | ||
var fill = 0.1 + 0.9 * i / (nFrames - 1); | ||
x = [-1]; | ||
y = [0]; | ||
|
||
// A wave across the top: | ||
for (j = 0; j < n; j++) { | ||
t = j / (n - 1); | ||
x.push(-1 - fill + (2 + 2 * fill) * t); | ||
y.push(fill + 0.05 * Math.sin(t * Math.PI * 2 * i)); | ||
} | ||
|
||
// Close the loop to draw the water: | ||
x.push(1, -1); | ||
y.push(0, 0); | ||
|
||
// Choose a name: | ||
name = 'frame' + i; | ||
|
||
// Store it in an array so we can animate in reverse order: | ||
reverseFrames.unshift(name); | ||
|
||
// Create the frame: | ||
frames.push({ | ||
name: name, | ||
data: [{x: x, y: y}], | ||
group: i < nFrames / 2 ? 'lower' : 'upper' | ||
}) | ||
} | ||
|
||
Plotly.plot('graph', [{ | ||
// Set up the initial water: | ||
x: frames[0].data[0].x, | ||
y: frames[0].data[0].y, | ||
mode: 'lines', | ||
fill: 'toself', | ||
showlegend: false, | ||
line: {simplify: false} | ||
}, { | ||
// Draw a glass: | ||
x: [-1, 1, 2.1, -2.1, -1], | ||
y: [0, 0, 1.1, 1.1, 0], | ||
mode: 'lines', | ||
fill: 'toself', | ||
showlegend: false, | ||
fillcolor: 'rgba(0, 0, 0, 0.1)', | ||
line: {color: 'rgba(100,100,100,0.2)'} | ||
}], { | ||
xaxis: {range: [-3, 3]}, | ||
yaxis: {range: [-0.1, 1.5]} | ||
}).then(function() { | ||
// Add the frames so we can animate them: | ||
Plotly.addFrames('graph', frames); | ||
}); | ||
|
||
// Stop the animation by animating to an empty set of frames: | ||
function stopAnimation () { | ||
Plotly.animate('graph', [], {mode: 'next'}); | ||
} | ||
|
||
function startAnimation (groupOrFrames, mode) { | ||
Plotly.animate('graph', groupOrFrames, { | ||
transition: { | ||
duration: 500, | ||
easing: 'linear' | ||
}, | ||
frame: { | ||
duration: 500, | ||
redraw: false, | ||
}, | ||
mode: mode | ||
}); | ||
} |
38 changes: 38 additions & 0 deletions
38
_posts/plotly_js/animations/2016-09-15-animations-object-constancy.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
--- | ||
name: Object Constancy | ||
plot_url: http://codepen.io/plotly/embed/LRNaWw/?height=500&theme-id=15263&default-tab=result | ||
language: plotly_js | ||
suite: animations | ||
order: 6 | ||
sitemap: false | ||
arrangement: horizontal | ||
markdown_content: | | ||
For scatter traces, you may wish to retain a marker's identity as it is updated. If you include an array of string ids with the trace, the marker identity will be retained. By shuffling the ids, the example below shuffles the markers each time the button is pressed. | ||
--- | ||
function shuffleInPlace(array) { | ||
for (var i = array.length - 1; i > 0; i--) { | ||
var j = Math.floor(Math.random() * (i + 1)); | ||
var temp = array[i]; | ||
array[i] = array[j]; | ||
array[j] = temp; | ||
} | ||
} | ||
|
||
var ids = ['1', '2', '3', '4', '5', '6']; | ||
|
||
Plotly.plot('graph', [{ | ||
x: [1, 0.5, -0.5, -1, -0.5, 0.5], | ||
y: [0, 0.866, 0.866, 0, -0.866, -0.866], | ||
ids: ids, | ||
mode: 'markers' | ||
}], { | ||
xaxis: {range: [-3, 3]}, | ||
yaxis: {range: [-2, 2]} | ||
}); | ||
|
||
function animateShuffle() { | ||
shuffleInPlace(ids); | ||
Plotly.animate('graph', [{ | ||
data: [{ids: ids}] | ||
}]); | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
To stay consistent with the other docs you can set the description to: How to animate D3.js-based line and scatter plots in JavaScript.
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.
Can do. The only reason I didn't is that it's not limited to scatter traces or D3-based traces. See: https://rreusser.github.io/animation-experiments/#3d (the timing is not great at the moment; needs a patch)
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.
Good point! How about: How to animate Plotly graphs in JavaScript.