# Ipyvolume¶

IPyvolume is a Python library to visualize 3d volumes and glyphs (e.g. 3d scatter plots), in the Jupyter notebook, with minimal configuration and effort. It is currently pre-1.0, so use at own risk. IPyvolume’s volshow is to 3d arrays what matplotlib’s imshow is to 2d arrays.

Other (more mature but possibly more difficult to use) related packages are yt, VTK and/or Mayavi.

Feedback and contributions are welcome: Github, Email or Twitter.

## Quick intro¶

### Volume¶

For quick resuls, use ipyvolume.widgets.quickvolshow. From a numpy array, we create two boxes, using slicing, and visualize it.

import numpy as np
import ipyvolume as ipv
V = np.zeros((128,128,128)) # our 3d array
# outer box
V[30:-30,30:-30,30:-30] = 0.75
V[35:-35,35:-35,35:-35] = 0.0
# inner box
V[50:-50,50:-50,50:-50] = 0.25
V[55:-55,55:-55,55:-55] = 0.0
ipv.quickvolshow(V, level=[0.25, 0.75], opacity=0.03, level_width=0.1, data_min=0, data_max=1)


### Scatter plot¶

Simple scatter plots are also supported.

import ipyvolume as ipv
import numpy as np
x, y, z = np.random.random((3, 10000))
ipv.quickscatter(x, y, z, size=1, marker="sphere")


### Quiver plot¶

Quiver plots are also supported, showing a vector at each point.

import ipyvolume as ipv
import numpy as np
x, y, z, u, v, w = np.random.random((6, 1000))*2-1
quiver = ipv.quickquiver(x, y, z, u, v, w, size=5)


### Mesh plot¶

And surface/mesh plots, showing surfaces or wireframes.

import ipyvolume as ipv
x, y, z, u, v = ipv.examples.klein_bottle(draw=False)
ipv.figure()
m = ipv.plot_mesh(x, y, z, wireframe=False)
ipv.squarelim()
ipv.show()


### Built on Ipywidgets¶

For anything more sophisticed, use ipyvolume.pylab, ipyvolume’s copy of matplotlib’s 3d plotting (+ volume rendering).

Since ipyvolume is built on ipywidgets, we can link widget’s properties.

import ipyvolume as ipv
import numpy as np
x, y, z, u, v, w = np.random.random((6, 1000))*2-1
selected = np.random.randint(0, 1000, 100)
ipv.figure()
quiver = ipv.quiver(x, y, z, u, v, w, size=5, size_selected=8, selected=selected)

from ipywidgets import FloatSlider, ColorPicker, VBox, jslink
size = FloatSlider(min=0, max=30, step=0.1)
size_selected = FloatSlider(min=0, max=30, step=0.1)
color = ColorPicker()
color_selected = ColorPicker()
VBox([ipv.gcc(), size, size_selected, color, color_selected])


Try changing the slider to the change the size of the vectors, or the colors.

## Quick installation¶

This will most likely work, otherwise read install

pip install ipyvolume
jupyter nbextension enable --py --sys-prefix ipyvolume
jupyter nbextension enable --py --sys-prefix widgetsnbextension


For conda/anaconda, use:

conda install -c conda-forge ipyvolume
pip install ipywidgets~=6.0.0b5 --user


Ipyvolume is an offspring project from vaex. Ipyvolume makes use of threejs, an excellent Javascript library for OpenGL/WebGL rendering.

## Contents¶

### Installation¶

#### Using pip¶

Advice: Make sure you use conda or virtualenv. If you are not a root user and want to use the --user argument for pip, you expose the installation to all python environments, which is a bad practice, make sure you know what you are doing.



#### For Jupyter lab users¶

The Jupyter lab extension is not enabled by default (yet).

$conda install -c conda-forge nodejs # or some other way to have a recent node$ jupyter labextension install jupyter labextension install @jupyter-widgets/jupyterlab-manager
$jupyter labextension install ipyvolume$ jupyter labextension install jupyter-threejs


#### Pre-notebook 5.3¶

If you are still using an old notebook version, ipyvolume and its dependend extension (widgetsnbextension) need to be enabled manually. If unsure, check which extensions are enabled:

$jupyter nbextention list  If not enabled, enable them: $ jupyter nbextension enable --py --sys-prefix ipyvolume
$jupyter nbextension enable --py --sys-prefix widgetsnbextension  #### Pip as user: (but really, do not do this)¶ You have been warned, do this only if you know what you are doing, this might hunt you in the future, and now is a good time to consider learning virtualenv or conda. $ pip install ipyvolume --user
$jupyter nbextension enable --py --user ipyvolume$ jupyter nbextension enable --py --user widgetsnbextension


#### Developer installation¶

$git clone https://github.com/maartenbreddels/ipyvolume.git$ cd ipyvolume
$pip install -e .$ jupyter nbextension install --py --symlink --sys-prefix ipyvolume
$jupyter nbextension enable --py --sys-prefix ipyvolume  For all cases make sure ipywidgets is enabled if you use Jupyter notebook version < 5.3 (using --user instead of --sys-prefix if doing a local install): $ jupyter nbextension enable --py --sys-prefix widgetsnbextension
$jupyter nbextension enable --py --sys-prefix pythreejs$ jupyter nbextension enable --py --sys-prefix ipywebrtc
$jupyter nbextension enable --py --sys-prefix ipyvolume  #### Developer workflow¶ ##### Jupyter notebook (classical)¶ Note: There is never a need to restart the notebook server, nbextensions are picked up after a page reload. Start this command: $ (cd js; npm run watch)


It will

• Watch for changes in the sourcecode and run the typescript compiler for transpilation of the src dir to the lib dir.
• Watch the lib dir, and webpack will build (among other things), ROOT/ipyvolume/static/index.js.

Refresh the page.

### Examples¶

#### Mixing ipyvolume with Bokeh¶

This example shows how the selection from a ipyvolume quiver plot can be controlled with a bokeh scatter plot and it’s selection tools.

##### Ipyvolume quiver plot¶

The 3d quiver plot is done using ipyvolume

:

import ipyvolume
import ipyvolume as ipv
import vaex


We load some data from vaex, but only use the first 10 000 samples for performance reasons of Bokeh.

:

ds = vaex.example()
N = 10000


We make a quiver plot using ipyvolume’s matplotlib’s style api.

:

ipv.figure()
quiver = ipv.quiver(ds.data.x[:N],  ds.data.y[:N],  ds.data.z[:N],
ds.data.vx[:N], ds.data.vy[:N], ds.data.vz[:N],
size=1, size_selected=5, color_selected="grey")
ipv.xyzlim(-30, 30)
ipv.show()

##### Bokeh scatter part¶

The 2d scatter plot is done using Bokeh.

:

from bokeh.io import output_notebook, show
from bokeh.plotting import figure
import ipyvolume.bokeh
output_notebook()

:

tools = "wheel_zoom,box_zoom,box_select,lasso_select,help,reset,"
p = figure(title="E Lz space", tools=tools, webgl=True, width=500, height=500)
r = p.circle(ds.data.Lz[:N], ds.data.E[:N],color="navy", alpha=0.2)
# A 'trick' from ipyvolume to link the selection (one way traffic atm)
show(p)


Now try doing a selection and see how the above 3d quiver plot reflects this selection.

[ ]:

# this code is currently broken
# import ipywidgets
#out = ipywidgets.Output()
#with out:
#    show(p)
#ipywidgets.HBox([out, ipv.gcc()])

##### Embedding in html¶

A bit of a hack, but it is possible to embed the widget and the bokeh part into a single html file (use at own risk).

:

from bokeh.resources import CDN
from bokeh.embed import components

script, div = components((p))
template_options = dict(extra_script_head=script + CDN.render_js() + CDN.render_css(),
body_pre="<h2>Do selections in 2d (bokeh)<h2>" + div + "<h2>And see the selection in ipyvolume<h2>")
ipyvolume.embed.embed_html("tmp/bokeh.html",
[ipv.gcc(), ipyvolume.bokeh.wmh], all_states=True,
template_options=template_options)

:

!open tmp/bokeh.html

[ ]:




#### Mixing ipyvolume with bqplot¶

This example shows how the selection from a ipyvolume quiver plot can be controlled with a bqplot scatter plot and it’s selection tools. We first get a small dataset from vaex

:

import numpy as np
import vaex

:

ds = vaex.example()
N = 2000 # for performance reasons we only do a subset
x, y, z, vx, vy, vz, Lz, E = [ds.columns[k][:N] for k in "x y z vx vy vz Lz E".split()]

##### bqplot scatter plot¶

And create a scatter plot with bqplot

:

import bqplot.pyplot as plt

:

plt.figure(1, title="E Lz space")
scatter = plt.scatter(Lz, E,
selected_style={'opacity': 0.2, 'size':1, 'stroke': 'red'},
unselected_style={'opacity': 0.2, 'size':1, 'stroke': 'blue'},
default_size=1,
)
plt.brush_selector()
plt.show()

##### Ipyvolume quiver plot¶

And use ipyvolume to create a quiver plot

:

import ipyvolume.pylab as p3

:

p3.clear()
quiver = p3.quiver(x, y, z, vx, vy, vz, size=2, size_selected=5, color_selected="blue")
p3.show()


Using jslink, we link the selected properties of both widgets, and we display them next to eachother using a VBox.

:

from ipywidgets import jslink, VBox

:

jslink((scatter, 'selected'), (quiver, 'selected'))

:

hbox = VBox([p3.current.container, plt.figure(1)])
hbox

##### Embedding¶

We embed the two widgets in an html file, creating a standlone plot.

:

import ipyvolume.embed
# if we don't do this, the bqplot will be really tiny in the standalone html
bqplot_layout = hbox.children.layout
bqplot_layout.min_width = "400px"

:

ipyvolume.embed.embed_html("bqplot.html", hbox, offline=True, devmode=True)

[ ]:

!open bqplot.html

[ ]:




#### MCMC & why 3d matters¶

This example (although quite artificial) shows that viewing a posterior (ok, I have flat priors) in 3d can be quite useful. While the 2d projection may look quite ‘bad’, the 3d volume rendering shows that much of the volume is empty, and the posterior is much better defined than it seems in 2d.

:

import pylab
import scipy.optimize as op
import emcee
import numpy as np
%matplotlib inline

:

# our 'blackbox' 3 parameter model which is highly degenerate
def f_model(x, a, b, c):
return x * np.sqrt(a**2 +b**2 + c**2) + a*x**2 + b*x**3

:

N = 100
a_true, b_true, c_true = -1., 2., 1.5

# our input and output
x = np.random.rand(N)*0.5#+0.5
y = f_model(x, a_true, b_true, c_true)

# + some (known) gaussian noise
error = 0.2
y += np.random.normal(0, error, N)

# and plot our data
pylab.scatter(x, y);
pylab.xlabel("$x$")
pylab.ylabel("$y$")

:

<matplotlib.text.Text at 0x10d7b35c0> :

# our likelihood
def lnlike(theta, x, y, error):
a, b, c = theta
model =  f_model(x, a, b, c)
chisq = 0.5*(np.sum((y-model)**2/error**2))
return -chisq
result = op.minimize(lambda *args: -lnlike(*args), [a_true, b_true, c_true], args=(x, y, error))
# find the max likelihood
a_ml, b_ml, c_ml = result["x"]
print("estimates", a_ml, b_ml, c_ml)
print("true values", a_true, b_true, c_true)
result["message"]

estimates 1.74022905195 -1.23351935318 -1.68793098984e-05
true values -1.0 2.0 1.5

:

'Optimization terminated successfully.'

:

# do the mcmc walk
ndim, nwalkers = 3, 100
pos = [result["x"] + np.random.randn(ndim)*0.1 for i in range(nwalkers)]
sampler = emcee.EnsembleSampler(nwalkers, ndim, lnlike, args=(x, y, error))
sampler.run_mcmc(pos, 1500);
samples = sampler.chain[:, 50:, :].reshape((-1, ndim))

##### Posterior in 2d¶
:

# plot the 2d pdfs
import corner
fig = corner.corner(samples, labels=["$a$", "$b$", "$c$"],
truths=[a_true, b_true, c_true]) ##### Posterior in 3d¶
:

import vaex
import scipy.ndimage
import ipyvolume

:

ds = vaex.from_arrays(a=samples[...,0].copy(), b=samples[...,1].copy(), c=samples[...,2].copy())
# get 2d histogram
v = ds.count(binby=["a", "b", "c"], shape=64)
# smooth it for visual pleasure
v = scipy.ndimage.gaussian_filter(v, 2)

:

ipyvolume.quickvolshow(v, lighting=True)


Note that actually a large part of the volume is empty.

[ ]: