Skip to content
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

[WIP] FEATURE: Convenience functions for volume rendering transfer functions #178

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ before_install:
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
- conda info -a
- conda create -q -n test-environment python=$PYTHON_VERSION numpy scipy runipy
- conda create -q -n test-environment python=$PYTHON_VERSION numpy scipy runipy matplotlib
- source activate test-environment
- conda install -c conda-forge pytest==3.8.1 pytest-cov bokeh nodejs matplotlib scikit-image shapely flake8
- pip install PyChromeDevTools
Expand Down
125 changes: 120 additions & 5 deletions ipyvolume/transferfunction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

from __future__ import absolute_import

__all__ = ['TransferFunction', 'TransferFunctionJsBumps', 'TransferFunctionWidgetJs3', 'TransferFunctionWidget3']

import ipywidgets as widgets
import matplotlib.colors
import matplotlib.cm
import numpy as np
import ipywidgets as widgets # we should not have widgets under two names
import traitlets
from traitlets import Unicode
from traitlets import Unicode, validate
from traittypes import Array

from . import serialize
import ipyvolume._version
from ipyvolume import serialize

__all__ = ['TransferFunction', 'TransferFunctionJsBumps', 'TransferFunctionWidgetJs3', 'TransferFunctionWidget3']

N = 1024
x = np.linspace(0, 1, N, endpoint=True)
Expand Down Expand Up @@ -136,3 +137,117 @@ def control(self, max_opacity=0.2):
widgets.HBox([widgets.Label(value="opacities:"), o1, o2, o3]),
]
)


def linear_transfer_function(color,
min_opacity=0,
max_opacity=0.05,
reverse_opacity=False,
n_elements = 256):
"""Transfer function of a single color and linear opacity.

:param color: Listlike RGB, or string with hexidecimal or named color.
RGB values should be within 0-1 range.
:param min_opacity: Minimum opacity, default value is 0.0.
Lowest possible value is 0.0, optional.
:param max_opacity: Maximum opacity, default value is 0.05.
Highest possible value is 1.0, optional.
:param reverse_opacity: Linearly decrease opacity, optional.
:param n_elements: Length of rgba array transfer function attribute.
:type color: listlike or string
:type min_opacity: float, int
:type max_opacity: float, int
:type reverse_opacity: bool
:type n_elements: int
:return: transfer_function
:rtype: ipyvolume TransferFunction

:Example:
>>> import ipyvolume as ipv
>>> green_tf = ipv.transfer_function.linear_transfer_function('green')
>>> ds = ipv.datasets.aquariusA2.fetch()
>>> ipv.volshow(ds.data[::4,::4,::4], tf=green_tf)
>>> ipv.show()

.. seealso:: matplotlib_transfer_function()
"""
r, g, b = matplotlib.colors.to_rgb(color)
opacity = np.linspace(min_opacity, max_opacity, num=n_elements)
if reverse_opacity:
opacity = np.flip(opacity, axis=0)
rgba = np.transpose(np.stack([[r] * n_elements,
[g] * n_elements,
[b] * n_elements,
opacity]))
transfer_function = TransferFunction(rgba=rgba)
return transfer_function


def matplotlib_transfer_function(colormap_name,
min_opacity=0,
max_opacity=0.05,
reverse_colormap=False,
reverse_opacity=False,
n_elements=256):
"""Transfer function from matplotlib colormaps.

:param colormap_name: name of matplotlib colormap
:param min_opacity: Minimum opacity, default value is 0.
Lowest possible value is 0, optional.
:param max_opacity: Maximum opacity, default value is 0.05.
Highest possible value is 1.0, optional.
:param reverse_colormap: reversed matplotlib colormap, optional.
:param reverse_opacity: Linearly decrease opacity, optional.
:param n_elements: Length of rgba array transfer function attribute.
:type colormap_name: str
:type min_opacity: float, int
:type max_opacity: float, int
:type reverse_colormap: bool
:type reverse_opacity: bool
:type n_elements: int
:return: transfer_function
:rtype: ipyvolume TransferFunction

:Example:
>>> import ipyvolume as ipv
>>> rgb = (0, 255, 0) # RGB value for green
>>> green_tf = ipv.transfer_function.matplotlib_transfer_function('bone')
>>> ds = ipv.datasets.aquariusA2.fetch()
>>> ipv.volshow(ds.data[::4,::4,::4], tf=green_tf)
>>> ipv.show()

.. seealso:: linear_transfer_function()
"""
cmap = matplotlib.cm.get_cmap(name=colormap_name)
rgba = np.array([cmap(i) for i in np.linspace(0, 1, n_elements)])
if reverse_colormap:
rgba = np.flip(rgba, axis=0)
# Create opacity values to overwrite default matplotlib opacity=1.0
opacity = np.linspace(min_opacity, max_opacity, num=n_elements)
if reverse_opacity:
opacity = np.flip(opacity, axis=0)
rgba[:,-1] = opacity # replace opacity=1 with actual opacity
transfer_function = TransferFunction(rgba=rgba)
return transfer_function


def predefined_transfer_functions():
"""Load predefined transfer functions into a dictionary.

:return: dictionary of predefined transfer functions.
:rtype: dict of ipyvolume TransferFunction instances
"""
transfer_functions = {}
# RGB primary and secondary colors
colors = ['red', 'green', 'blue', 'yellow', 'magenta', 'cyan',
'black', 'gray', 'white']
for color in colors:
tf = linear_transfer_function(color)
transfer_functions[color] = tf
tf_reversed = linear_transfer_function(rgb, reverse_opacity=True)
transfer_functions[color_key + '_r'] = tf_reversed
# All matplotlib colormaps
matplotlib_colormaps = matplotlib.cm.cmap_d.keys()
for colormap in matplotlib_colormaps:
transfer_functions[colormap] = matplotlib_transfer_function(colormap)
return transfer_functions