3
3
from __future__ import absolute_import
4
4
from __future__ import division
5
5
import pythreejs
6
+ from typing import List , Union
7
+
6
8
7
9
__all__ = [
8
10
'current' ,
29
31
'animation_control' ,
30
32
'gcc' ,
31
33
'transfer_function' ,
34
+ 'transfer_function_discrete' ,
32
35
'plot_isosurface' ,
33
36
'volshow' ,
34
37
'save' ,
@@ -894,6 +897,48 @@ def gcc():
894
897
return current .container
895
898
896
899
900
+ def transfer_function_discrete (
901
+ n ,
902
+ colors : List [str ] = ["red" , "green" , "blue" ],
903
+ labels : Union [None , List [str ]] = None ,
904
+ opacity : Union [float , List [float ]] = 0.1 ,
905
+ enabled : Union [bool , List [bool ]] = True ,
906
+ controls = True ,
907
+ ):
908
+ """Create a discrete transfer function with n layers.
909
+
910
+ Each (integer) value of the volumetric data maps to a single color.
911
+
912
+ :param n: number of layers
913
+ :param colors: list of colors, can be any valid HTML color string
914
+ :param labels: list of labels, if None, labels will be "Layer 0", "Layer 1", etc.
915
+ :param opacity: opacity of each layer, can be a single value or a list of values
916
+ :param enabled: whether each layer is enabled, can be a single value or a list of values
917
+ :param controls: whether to add the controls to the current container
918
+
919
+ """
920
+ if isinstance (opacity , float ):
921
+ opacity = [opacity ] * len (colors )
922
+ if isinstance (enabled , bool ):
923
+ enabled = [enabled ] * len (colors )
924
+
925
+ def ensure_length (x ):
926
+ repeat = (n + len (colors ) - 1 ) // len (colors )
927
+ return (x * repeat )[:n ]
928
+
929
+ if labels is None :
930
+ labels = []
931
+ for i in range (n ):
932
+ labels .append (f"Layer { i } " )
933
+
934
+ tf = ipv .TransferFunctionDiscrete (colors = ensure_length (colors ), opacities = ensure_length (opacity ), enabled = ensure_length (enabled ), labels = ensure_length (labels ))
935
+ gcf () # make sure a current container/figure exists
936
+ if controls :
937
+ current .container .children = [tf .control ()] + current .container .children
938
+
939
+ return tf
940
+
941
+
897
942
def transfer_function (
898
943
level = [0.1 , 0.5 , 0.9 ], opacity = [0.01 , 0.05 , 0.1 ], level_width = 0.1 , controls = True , max_opacity = 0.2
899
944
):
@@ -1029,8 +1074,7 @@ def volshow(
1029
1074
):
1030
1075
"""Visualize a 3d array using volume rendering.
1031
1076
1032
- Currently only 1 volume can be rendered.
1033
-
1077
+ If the data is of type int8 or bool, :any:`a discrete transfer function will be used <ipv.discrete_transfer_function>`
1034
1078
1035
1079
:param data: 3d numpy array
1036
1080
:param origin: origin of the volume data, this is to match meshes which have a different origin
@@ -1040,7 +1084,7 @@ def volshow(
1040
1084
:param float data_max: maximum value to consider for data, if None, computed using np.nanmax
1041
1085
:parap int max_shape: maximum shape for the 3d cube, if larger, the data is reduced by skipping/slicing (data[::N]),
1042
1086
set to None to disable.
1043
- :param tf: transfer function (or a default one)
1087
+ :param tf: transfer function (or a default one, based on the data )
1044
1088
:param bool stereo: stereo view for virtual reality (cardboard and similar VR head mount)
1045
1089
:param ambient_coefficient: lighting parameter
1046
1090
:param diffuse_coefficient: lighting parameter
@@ -1060,12 +1104,18 @@ def volshow(
1060
1104
"""
1061
1105
fig = gcf ()
1062
1106
1063
- if tf is None :
1064
- tf = transfer_function (level , opacity , level_width , controls = controls , max_opacity = max_opacity )
1065
1107
if data_min is None :
1066
1108
data_min = np .nanmin (data )
1067
1109
if data_max is None :
1068
1110
data_max = np .nanmax (data )
1111
+ if tf is None :
1112
+ if (data .dtype == np .uint8 ) or (data .dtype == bool ):
1113
+ if data .dtype == bool :
1114
+ data_max = 1
1115
+
1116
+ tf = transfer_function_discrete (n = data_max + 1 )
1117
+ else :
1118
+ tf = transfer_function (level , opacity , level_width , controls = controls , max_opacity = max_opacity )
1069
1119
if memorder == 'F' :
1070
1120
data = data .T
1071
1121
0 commit comments