import ipywidgets as widgets
import ipywidgets
from traitlets import Unicode, Integer
import traitlets
from traittypes import Array
import logging
import numpy as np
from .serialize import array_cube_png_serialization, array_serialization, array_binary_serialization, \
create_array_binary_serialization
from .transferfunction import *
import warnings
import ipyvolume
logger = logging.getLogger("ipyvolume")
_last_volume_renderer = None
@widgets.register('ipyvolume.Scatter')
class Scatter(widgets.DOMWidget):
_view_name = Unicode('ScatterView').tag(sync=True)
_view_module = Unicode('ipyvolume').tag(sync=True)
_model_name = Unicode('ScatterModel').tag(sync=True)
_model_module = Unicode('ipyvolume').tag(sync=True)
x = Array(default_value=None).tag(sync=True, **create_array_binary_serialization('x'))
y = Array(default_value=None).tag(sync=True, **create_array_binary_serialization('y'))
z = Array(default_value=None).tag(sync=True, **create_array_binary_serialization('z'))
vx = Array(default_value=None,allow_none=True).tag(sync=True, **create_array_binary_serialization('vx'))
vy = Array(default_value=None,allow_none=True).tag(sync=True, **create_array_binary_serialization('vy'))
vz = Array(default_value=None,allow_none=True).tag(sync=True, **create_array_binary_serialization('vz'))
selected = Array(default_value=None,allow_none=True).tag(sync=True, **array_serialization)
sequence_index = Integer(default_value=0).tag(sync=True)
size = traitlets.Union([traitlets.Float().tag(sync=True),
Array(default_value=None,allow_none=True).tag(sync=True, **array_serialization)],
default_value=0.1).tag(sync=True)
size_selected = traitlets.Float(0.02).tag(sync=True)
color = traitlets.Union([Unicode().tag(sync=True),
Array(default_value=None,allow_none=True).tag(sync=True, **array_serialization)],
default_value="red").tag(sync=True)
color_selected = traitlets.Unicode(default_value="white").tag(sync=True)
geo = traitlets.Unicode('diamond').tag(sync=True)
@widgets.register('ipyvolume.VolumeRendererThree')
class VolumeRendererThree(widgets.DOMWidget):
"""Widget class representing a volume (rendering) using three.js"""
_view_name = Unicode('VolumeRendererThreeView').tag(sync=True)
_view_module = Unicode('ipyvolume').tag(sync=True)
_model_name = Unicode('VolumeRendererThreeModel').tag(sync=True)
_model_module = Unicode('ipyvolume').tag(sync=True)
volume_data = Array(default_value=None, allow_none=True).tag(sync=True, **array_cube_png_serialization)
data_min = traitlets.CFloat().tag(sync=True)
data_max = traitlets.CFloat().tag(sync=True)
tf = traitlets.Instance(TransferFunction, allow_none=True).tag(sync=True, **ipywidgets.widget_serialization)
angle1 = traitlets.Float(0.1).tag(sync=True)
angle2 = traitlets.Float(0.2).tag(sync=True)
scatters = traitlets.List(traitlets.Instance(Scatter), [], allow_none=False).tag(sync=True, **ipywidgets.widget_serialization)
animation = traitlets.Float(1000.0).tag(sync=True)
animation_exponent = traitlets.Float(.5).tag(sync=True)
ambient_coefficient = traitlets.Float(0.5).tag(sync=True)
diffuse_coefficient = traitlets.Float(0.8).tag(sync=True)
specular_coefficient = traitlets.Float(0.5).tag(sync=True)
specular_exponent = traitlets.Float(5).tag(sync=True)
stereo = traitlets.Bool(False).tag(sync=True)
screen_capture_enabled = traitlets.Bool(False).tag(sync=True)
screen_capture_mime_type = traitlets.Unicode(default_value='image/png').tag(sync=True)
screen_capture_data = traitlets.Unicode(default_value=None, allow_none=True).tag(sync=True)
fullscreen = traitlets.Bool(False).tag(sync=True)
camera_control = traitlets.Unicode(default_value='trackball').tag(sync=True)
width = traitlets.CInt(500).tag(sync=True)
height = traitlets.CInt(400).tag(sync=True)
downscale = traitlets.CInt(1).tag(sync=True)
show = traitlets.Unicode("Volume").tag(sync=True) # for debugging
xlim = traitlets.List(traitlets.CFloat, default_value=[0, 1], minlen=2, maxlen=2).tag(sync=True)
ylim = traitlets.List(traitlets.CFloat, default_value=[0, 1], minlen=2, maxlen=2).tag(sync=True)
zlim = traitlets.List(traitlets.CFloat, default_value=[0, 1], minlen=2, maxlen=2).tag(sync=True)
xlabel = traitlets.Unicode("x").tag(sync=True)
ylabel = traitlets.Unicode("y").tag(sync=True)
zlabel = traitlets.Unicode("z").tag(sync=True)
style = traitlets.Dict(default_value=ipyvolume.style.default).tag(sync=True)
#xlim = traitlets.Tuple(traitlets.CFloat(0), traitlets.CFloat(1)).tag(sync=True)
#y#lim = traitlets.Tuple(traitlets.CFloat(0), traitlets.CFloat(1)).tag(sync=True)
#zlim = traitlets.Tuple(traitlets.CFloat(0), traitlets.CFloat(1)).tag(sync=True)
def _volume_widets(v, lighting=False):
import ipywidgets
#angle1 = ipywidgets.FloatSlider(min=0, max=np.pi*2, value=v.angle1, description="angle1")
#angle2 = ipywidgets.FloatSlider(min=0, max=np.pi*2, value=v.angle2, description="angle2")
#ipywidgets.jslink((v, 'angle1'), (angle1, 'value'))
#ipywidgets.jslink((v, 'angle2'), (angle2, 'value'))
if lighting:
ambient_coefficient = ipywidgets.FloatSlider(min=0, max=1, step=0.001, value=v.ambient_coefficient, description="ambient")
diffuse_coefficient = ipywidgets.FloatSlider(min=0, max=1, step=0.001, value=v.diffuse_coefficient, description="diffuse")
specular_coefficient = ipywidgets.FloatSlider(min=0, max=1, step=0.001, value=v.specular_coefficient, description="specular")
specular_exponent = ipywidgets.FloatSlider(min=0, max=10, step=0.001, value=v.specular_exponent, description="specular exp")
#angle2 = ipywidgets.FloatSlider(min=0, max=np.pi*2, value=v.angle2, description="angle2")
ipywidgets.jslink((v, 'ambient_coefficient'), (ambient_coefficient, 'value'))
ipywidgets.jslink((v, 'diffuse_coefficient'), (diffuse_coefficient, 'value'))
ipywidgets.jslink((v, 'specular_coefficient'), (specular_coefficient, 'value'))
ipywidgets.jslink((v, 'specular_exponent'), (specular_exponent, 'value'))
widgets_bottom = [ipywidgets.HBox([ambient_coefficient, diffuse_coefficient]),
ipywidgets.HBox([specular_coefficient, specular_exponent])]
else:
widgets_bottom = []
v.ambient_coefficient = 1
v.diffuse_coefficient = 0
v.specular_coefficient = 0
if 1:
stereo = widgets.ToggleButton(value=v.stereo, description='stereo', icon='eye')
fullscreen = widgets.ToggleButton(value=v.stereo, description='fullscreen', icon='arrows-alt')
ipywidgets.jslink((v, 'stereo'), (stereo, 'value'))
ipywidgets.jslink((v, 'fullscreen'), (fullscreen, 'value'))
widgets_bottom += [ipywidgets.HBox([stereo,fullscreen])]
return ipywidgets.VBox(
[v.tf.control(), v,
] + widgets_bottom# , ipywidgets.HBox([angle1, angle2])
)
[docs]def volshow(*args, **kwargs):
"""Deprecated: please use ipyvolume.quickvol or use the ipyvolume.pylab interface"""
warnings.warn("Please use ipyvolume.quickvol or use the ipyvolume.pylab interface", DeprecationWarning, stacklevel=2)
return quickvolshow(*args, **kwargs)
[docs]def quickquiver(x, y, z, u, v, w, **kwargs):
import ipyvolume.pylab as p3
p3.figure()
p3.quiver(x, y, z, u, v, w, **kwargs)
return p3.current.container
[docs]def quickscatter(x, y, z, **kwargs):
import ipyvolume.pylab as p3
p3.figure()
p3.scatter(x, y, z, **kwargs)
return p3.current.container
[docs]def quickvolshow(data, lighting=False, data_min=None, data_max=None, tf=None, stereo=False,
width=400, height=500,
ambient_coefficient=0.5, diffuse_coefficient=0.8,
specular_coefficient=0.5, specular_exponent=5,
downscale=1,
level=[0.1, 0.5, 0.9], opacity=[0.01, 0.05, 0.1], level_width=0.1, **kwargs):
"""
Visualize a 3d array using volume rendering
:param data: 3d numpy array
:param lighting: boolean, to use lighting or not, if set to false, lighting parameters will be overriden
:param data_min: minimum value to consider for data, if None, computed using np.nanmin
:param data_max: maximum value to consider for data, if None, computed using np.nanmax
:param tf: transfer function (see ipyvolume.transfer_function, or use the argument below)
:param stereo: stereo view for virtual reality (cardboard and similar VR head mount)
:param width: width of rendering surface
:param height: height of rendering surface
:param ambient_coefficient: lighting parameter
:param diffuse_coefficient: lighting parameter
:param specular_coefficient: lighting parameter
:param specular_exponent: lighting parameter
:param downscale: downscale the rendering for better performance, for instance when set to 2, a 512x512 canvas will show a 256x256 rendering upscaled, but it will render twice as fast.
:param level: level(s) for the where the opacity in the volume peaks, maximum sequence of length 3
:param opacity: opacity(ies) for each level, scalar or sequence of max length 3
:param level_width: width of the (gaussian) bumps where the opacity peaks, scalar or sequence of max length 3
:param kwargs: extra argument passed to Volume and default transfer function
:return:
"""
if tf is None: # TODO: should this just call the pylab interface?
#tf = TransferFunctionJsBumps(**kwargs)
tf_kwargs = {}
# level, opacity and widths can be scalars
try:
level[0]
except:
level = [level]
try:
opacity[0]
except:
opacity = [opacity] * 3
try:
level_width[0]
except:
level_width = [level_width] * 3
#clip off lists
min_length = min(len(level), len(level_width), len(opacity))
level = list(level[:min_length])
opacity = list(opacity[:min_length])
level_width = list(level_width[:min_length])
# append with zeros
while len(level) < 3:
level.append(0)
while len(opacity) < 3:
opacity.append(0)
while len(level_width) < 3:
level_width.append(0)
for i in range(1,4):
tf_kwargs["level"+str(i)] = level[i-1]
tf_kwargs["opacity"+str(i)] = opacity[i-1]
tf_kwargs["width"+str(i)] = level_width[i-1]
tf = TransferFunctionWidgetJs3(**tf_kwargs)
if data_min is None:
data_min = np.nanmin(data)
if data_max is None:
data_max = np.nanmax(data)
v = VolumeRendererThree(volume_data=data, data_min=data_min, data_max=data_max, stereo=stereo,
width=width, height=height,
ambient_coefficient=ambient_coefficient,
diffuse_coefficient=diffuse_coefficient,
specular_coefficient=specular_coefficient,
specular_exponent=specular_exponent,
tf=tf, **kwargs)
box = _volume_widets(v, lighting=lighting)
return box
def scatter(x, y, z, color=(1,0,0), s=0.01):
global _last_figure;
fig = _last_figure
if fig is None:
fig = volshow(None)
fig.scatter = Scatter(x=x, y=y, z=z, color=color, size=s)
fig.volume.scatter = fig.scatter
return fig