diff --git a/panel/pane/vtk/vtk.py b/panel/pane/vtk/vtk.py index ac882cf88f..244e252899 100644 --- a/panel/pane/vtk/vtk.py +++ b/panel/pane/vtk/vtk.py @@ -679,9 +679,9 @@ def register_serializer(cls, class_type, serializer): cls._serializers.update({class_type:serializer}) def _volume_from_array(self, sub_array): - return dict(buffer=base64encode(sub_array.ravel(order='F' if sub_array.flags['F_CONTIGUOUS'] else 'C')), - dims=sub_array.shape if sub_array.flags['F_CONTIGUOUS'] else sub_array.shape[::-1], - spacing=self._sub_spacing if sub_array.flags['F_CONTIGUOUS'] else self._sub_spacing[::-1], + return dict(buffer=base64encode(sub_array.ravel(order='F')), + dims=sub_array.shape, + spacing=self._sub_spacing, origin=self.origin, data_range=(sub_array.min(), sub_array.max()), dtype=sub_array.dtype.name) @@ -700,10 +700,10 @@ def _get_volume_data(self): def volume_serializer(inst): imageData = inst.object array = numpy_support.vtk_to_numpy(imageData.GetPointData().GetScalars()) - dims = imageData.GetDimensions()[::-1] - inst.spacing = imageData.GetSpacing()[::-1] + dims = imageData.GetDimensions() + inst.spacing = imageData.GetSpacing() inst.origin = imageData.GetOrigin() - return inst._volume_from_array(inst._subsample_array(array.reshape(dims, order='C'))) + return inst._volume_from_array(inst._subsample_array(array.reshape(dims, order='F'))) VTKVolume.register_serializer(vtk.vtkImageData, volume_serializer) serializer = volume_serializer @@ -722,7 +722,7 @@ def _subsample_array(self, array): if any([d_f > 1 for d_f in dowsnscale_factor]): try: import scipy.ndimage as nd - sub_array = nd.interpolation.zoom(array, zoom=[1 / d_f for d_f in dowsnscale_factor], order=0) + sub_array = nd.interpolation.zoom(array, zoom=[1 / d_f for d_f in dowsnscale_factor], order=0, mode="nearest") except ImportError: sub_array = array[::int(np.ceil(dowsnscale_factor[0])), ::int(np.ceil(dowsnscale_factor[1])), diff --git a/panel/tests/pane/test_vtk.py b/panel/tests/pane/test_vtk.py index 93bb4f3429..6eb85ad661 100644 --- a/panel/tests/pane/test_vtk.py +++ b/panel/tests/pane/test_vtk.py @@ -370,3 +370,46 @@ def test_vtkvol_pane_from_image_data(document, comm): # Cleanup pane._cleanup(model) assert pane._models == {} + +@vtk_available +def test_vtkvol_serialization_coherence(document, comm): + from vtk.util import numpy_support + + data_matrix = np.zeros([50, 75, 100], dtype=np.uint8) + data_matrix[0:35, 0:35, 0:35] = 50 + data_matrix[25:50, 25:55, 25:55] = 100 + data_matrix[45:50, 45:74, 45:100] = 150 + + origin = (0, 10, 20) + spacing = (3,2,1) + + data_matrix_c = np.ascontiguousarray(data_matrix) + data_matrix_f = np.asfortranarray(data_matrix) + image_data = vtk.vtkImageData() + image_data.SetDimensions(*data_matrix.shape) + image_data.SetOrigin(*origin) + image_data.SetSpacing(*spacing) + vtk_arr = numpy_support.numpy_to_vtk(data_matrix.ravel(order='F')) + image_data.GetPointData().SetScalars(vtk_arr) + + p_c = VTKVolume(data_matrix_c, origin=origin, spacing=spacing) + p_f = VTKVolume(data_matrix_f, origin=origin, spacing=spacing) + p_id = VTKVolume(image_data) + assert p_c._sub_spacing == p_f._sub_spacing == p_id._sub_spacing == spacing + vd_c = p_c._get_volume_data() + vd_f = p_f._get_volume_data() + vd_id = p_id._get_volume_data() + data_decoded = np.frombuffer(base64.b64decode(vd_c["buffer"]), dtype=vd_c["dtype"]).reshape(vd_c["dims"], order="F") + assert np.alltrue(data_decoded==data_matrix) + assert vd_id == vd_c == vd_f + + + + p_c_ds = VTKVolume(data_matrix_c, origin=origin, spacing=spacing, max_data_size=0.1) + p_f_ds = VTKVolume(data_matrix_f, origin=origin, spacing=spacing, max_data_size=0.1) + p_id_ds = VTKVolume(image_data, max_data_size=0.1) + assert p_c_ds._sub_spacing == p_f_ds._sub_spacing == p_id_ds._sub_spacing != spacing + vd_c_ds = p_c_ds._get_volume_data() + vd_f_ds = p_f_ds._get_volume_data() + vd_id_ds = p_id_ds._get_volume_data() + assert vd_id_ds == vd_c_ds == vd_f_ds