Animation

All (or most of) the changes in scatter and quiver plots are (linearly) interpolated. On top top that, scatter plots and quiver plots can take a sequence of arrays (the first dimension), where only one array is visualized. Together this can make smooth animations with coarse timesteps. Lets see an example.

In [1]:
import ipyvolume.pylab as p3
import numpy as np

Basic animation

In [2]:
# only x is a sequence of arrays
x = np.array([[-1, -0.8], [1, -0.1], [0., 0.5]])
y = np.array([0.0, 0.0])
z = np.array([0.0, 0.0])
p3.figure()
s = p3.scatter(x, y, z)
p3.xyzlim(-1, 1)
p3.animate_glyphs(s) # shows controls for animation controls
p3.show()

You can control which array to visualize, using the scatter.sequence_index property. Actually, the pylab.animate_glyphs is connecting the Slider and Play button to that property, but you can also set it from Python.

In [3]:
s.sequence_index = 1

Animating color and size

We now demonstrate that you can also animate color and size

In [4]:
# create 2d grids: x, y, and r
u = np.linspace(-10, 10, 25)
x, y = np.meshgrid(u, u)
r = np.sqrt(x**2+y**2)
print("x,y and z are of shape", x.shape)
# and turn them into 1d
x = x.flatten()
y = y.flatten()
r = r.flatten()
print("and flattened of shape", x.shape)
x,y and z are of shape (25, 25)
and flattened of shape (625,)

Now we only animate the z component

In [5]:
# create a sequence of 15 time elements
time = np.linspace(0, np.pi*2, 15)
z = np.array([(np.cos(r + t) * np.exp(-r/5)) for t in time])
print("z is of shape", z.shape)
z is of shape (15, 625)
In [6]:
# draw the scatter plot, and add controls with animate_glyphs
p3.figure()
s = p3.scatter(x, z, y, marker="sphere")
p3.animate_glyphs(s, interval=200)
p3.ylim(-3,3)
p3.show()
In [7]:
# Now also include, color, which containts rgb values
color = np.array([[np.cos(r + t), 1-np.abs(z[i]), 0.1+z[i]*0] for i, t in enumerate(time)])
size = (z+1)
print("color is of shape", color.shape)
color is of shape (15, 3, 625)

color is of the wrong shape, the last dimension should contain the rgb value, i.e. the shape of should be (15, 2500, 3)

In [8]:
color = np.transpose(color, (0, 2, 1)) # flip the last axes
In [9]:
p3.figure()
s = p3.scatter(x, z, y, color=color, size=size, marker="sphere")
p3.animate_glyphs(s, interval=200)
p3.ylim(-3,3)
p3.show()
/Users/maartenbreddels/anaconda3/lib/python3.5/site-packages/traitlets/traitlets.py:565: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  silent = bool(old_value == new_value)

Performance

By default, data is transferred from Python to the Notebook (browser), using JSON. This may be slow for large volumes of data. To get better performance, change the following:

In [ ]:
import ipyvolume.serialize
ipyvolume.serialize.performance = 1 # 1 for binary, 0 for JSON

This will transfer all the data (numpy arrays) in binary, leading to a huge increase in performance. The downside (that is why it is not the default) is that embedding it in html (i.e. p3.save(..)) is not supported at the moment.

Animated quiver

Not only scatter plots can be animated, quiver as well, so the direction vector (vx, vy, vz) can also be animated, as shown in the example below, which is a (subsample of) a simulation of a small galaxy orbiting a host galaxy (not visible).

In [10]:
import ipyvolume.datasets
stream = ipyvolume.datasets.animated_stream.fetch()
print("shape of steam data", stream.data.shape) # first dimension contains x, y, z, vx, vy, vz, then time, then particle
shape of steam data (6, 200, 1250)
In [11]:
fig = p3.figure()
# instead of doing x=stream.data[0], y=stream.data[1], ... vz=stream.data[5], use *stream.data
# limit to 50 timesteps to avoid having a huge notebook
q = p3.quiver(*stream.data[:,0:50,:200], color="red", size=7)
p3.style.use("dark") # looks better
p3.animate_glyphs(q, interval=200)
p3.show()
In [ ]:
fig.animation = 0 # set to 0 for no interpolation
In [ ]: