diff --git a/.travis.yml b/.travis.yml index 130d3257..efce4487 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/ipyvolume/transferfunction.py b/ipyvolume/transferfunction.py index 586e1bd8..700900f7 100644 --- a/ipyvolume/transferfunction.py +++ b/ipyvolume/transferfunction.py @@ -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) @@ -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