def test_reordering(): """ Test indexing into a LayerList by name """ layers = LayerList() layer_a = Image(np.random.random((10, 10)), name='image_a') layer_b = Image(np.random.random((15, 15)), name='image_b') layer_c = Image(np.random.random((15, 15)), name='image_c') layers.append(layer_a) layers.append(layer_b) layers.append(layer_c) # Rearrange layers by tuple layers[:] = layers[(1, 0, 2)] assert list(layers) == [layer_b, layer_a, layer_c] # Swap layers by name layers['image_b', 'image_c'] = layers['image_c', 'image_b'] assert list(layers) == [layer_c, layer_a, layer_b] # Reverse layers layers.reverse() assert list(layers) == [layer_b, layer_a, layer_c]
def test_narrow_thumbnail(): """Ensure that the thumbnail generation works for very narrow images. See: https://github.com/napari/napari/issues/641 and https://github.com/napari/napari/issues/489 """ image = np.random.random((1, 2048)) layer = Image(image) layer._update_thumbnail() thumbnail = layer.thumbnail[..., :3] # ignore alpha channel middle_row = thumbnail.shape[0] // 2 assert np.all(thumbnail[:middle_row - 1] == 0) assert np.all(thumbnail[middle_row + 1:] == 0) assert np.mean(thumbnail[middle_row - 1:middle_row + 1]) > 0
def test_negative_image(): """Test instantiating Image layer with negative data.""" shape = (10, 15) np.random.seed(0) # Data between -1.0 and 1.0 data = 2 * np.random.random(shape) - 1.0 layer = Image(data) assert np.all(layer.data == data) assert layer.ndim == len(shape) assert layer.shape == shape assert layer.dims.range == [(0, m, 1) for m in shape] assert layer.rgb == False assert layer._data_view.shape == shape[-2:] # Data between -10 and 10 data = 20 * np.random.random(shape) - 10 layer = Image(data) assert np.all(layer.data == data) assert layer.ndim == len(shape) assert layer.shape == shape assert layer.dims.range == [(0, m, 1) for m in shape] assert layer.rgb == False assert layer._data_view.shape == shape[-2:]
def test_changing_image(): """Test changing Image data.""" shape_a = (10, 15) shape_b = (20, 12) np.random.seed(0) data_a = np.random.random(shape_a) data_b = np.random.random(shape_b) layer = Image(data_a) layer.data = data_b assert np.all(layer.data == data_b) assert layer.ndim == len(shape_b) np.testing.assert_array_equal(layer.extent.data[1] + 1, shape_b) assert layer.rgb is False assert layer._data_view.shape == shape_b[-2:]
def test_random_image(): """Test instantiating Image layer with random 2D data.""" shape = (10, 15) np.random.seed(0) data = np.random.random(shape) layer = Image(data) assert np.all(layer.data == data) assert layer.ndim == len(shape) assert layer.shape == shape assert layer.dims.range == [(0, m, 1) for m in shape] assert layer.rgb is False assert layer.is_pyramid is False assert layer._data_pyramid is None assert layer._data_view.shape == shape[-2:]
def test_world_extent_mixed_flipped(): """Test world extent after adding data with a flip.""" # Flipped data results in a negative scale value which should be # made positive when taking into consideration for the step size # calculation np.random.seed(0) layers = LayerList() layer = Image( np.random.random((15, 15)), affine=[[0, 1, 0], [1, 0, 0], [0, 0, 1]] ) layers.append(layer) np.testing.assert_allclose(layer._data_to_world.scale, (1, -1)) np.testing.assert_allclose(layers.extent.step, (1, 1))
def test_stack_to_images_rgb(): """Test 3 channel RGB image (channel axis = -1) into single channels.""" data = np.random.randint(0, 100, (10, 128, 128, 3)) stack = Image(data) images = stack_to_images(stack, -1, colormap=None) assert isinstance(images, list) assert len(images) == 3 for i in images: assert type(stack) == type(i) assert i.data.shape == (10, 128, 128) assert i.scale.shape == (3, ) assert i.rgb is False
def test_switching_displayed_dimensions(): """Test instantiating data then switching to displayed.""" shape = (10, 15, 20) np.random.seed(0) data = np.random.random(shape) layer = Image(data) assert np.all(layer.data == data) assert layer.ndim == len(shape) np.testing.assert_array_equal(layer.extent.data[1] + 1, shape) # check displayed data is initially 2D assert layer._data_view.shape == shape[-2:] layer._slice_dims(ndisplay=3) # check displayed data is now 3D assert layer._data_view.shape == shape[-3:] layer._slice_dims(ndisplay=2) # check displayed data is now 2D assert layer._data_view.shape == shape[-2:] layer = Image(data) layer._slice_dims(ndisplay=3) assert np.all(layer.data == data) assert layer.ndim == len(shape) np.testing.assert_array_equal(layer.extent.data[1] + 1, shape) # check displayed data is initially 3D assert layer._data_view.shape == shape[-3:] layer._slice_dims(ndisplay=2) # check displayed data is now 2D assert layer._data_view.shape == shape[-2:] layer._slice_dims(ndisplay=3) # check displayed data is now 3D assert layer._data_view.shape == shape[-3:]
def test_changing_image(): """Test changing Image data.""" shape_a = (10, 15) shape_b = (20, 12) np.random.seed(0) data_a = np.random.random(shape_a) data_b = np.random.random(shape_b) layer = Image(data_a) layer.data = data_b assert np.all(layer.data == data_b) assert layer.ndim == len(shape_b) assert layer.shape == shape_b assert layer.dims.range == [(0, m, 1) for m in shape_b] assert layer.rgb is False assert layer._data_view.shape == shape_b[-2:]
def test_scale(): """Test instantiating anisotropic 3D volume.""" shape = (10, 15, 20) scale = [3, 1, 1] full_shape = tuple(np.multiply(shape, scale)) np.random.seed(0) data = np.random.random(shape) layer = Image(data, scale=scale) layer._slice_dims(ndisplay=3) assert np.all(layer.data == data) assert layer.ndim == len(shape) np.testing.assert_array_equal(layer.extent.world[1] + layer.extent.step, full_shape) # Note that the scale appears as the step size in the range assert layer._data_view.shape == shape[-3:]
def test_instiantiate_with_experimental_slicing_plane_dict(): """Test that an image layer can be instantiated with plane parameters in a dictionary. """ plane_parameters = { 'position': (32, 32, 32), 'normal': (1, 1, 1), 'thickness': 22, } image = Image(np.ones((32, 32, 32)), experimental_slicing_plane=plane_parameters) for k, v in plane_parameters.items(): if k == 'normal': v = tuple(v / np.linalg.norm(v)) assert v == getattr(image.experimental_slicing_plane, k, v)
def test_multiscale_data_protocol(): """Test multiscale data provides basic data protocol.""" shapes = [(2, 5, 20, 20), (2, 5, 10, 10), (2, 5, 5, 5)] np.random.seed(0) data = [np.random.random(s) for s in shapes] layer = Image(data, multiscale=True) assert '3 levels' in repr(layer.data) assert layer.data == data assert layer.data_raw is data assert layer.data is not data assert layer.multiscale is True assert layer.data.dtype == float assert layer.data.shape == shapes[0] assert isinstance(layer.data[0], np.ndarray)
def test_images_to_stack_with_scale(): """Test that 3-Image list is combined to stack with scale and translate.""" images = [ Image(np.random.randint(0, 255, (10, 128, 128))) for _ in range(3) ] stack = images_to_stack( images, 1, colormap='green', scale=(3, 1, 1, 1), translate=(1, 0, 2, 3) ) assert isinstance(stack, Image) assert stack.data.shape == (10, 3, 128, 128) assert stack.colormap.name == 'green' assert list(stack.scale) == [3, 1, 1, 1] assert list(stack.translate) == [1, 0, 2, 3]
def test_data_to_world_2d_scale_translate_affine_composed(): data = np.ones((4, 3)) scale = (3, 2) translate = (-4, 8) affine = [[4, 0, 0], [0, 1.5, 0], [0, 0, 1]] image = Image(data, scale=scale, translate=translate, affine=affine) np.testing.assert_array_equal(image.scale, scale) np.testing.assert_array_equal(image.translate, translate) np.testing.assert_array_equal(image.affine, affine) np.testing.assert_almost_equal( image._data_to_world.affine_matrix, ((12, 0, -16), (0, 3, 12), (0, 0, 1)), )
def test_changing_volume(): """Test changing Image data.""" shape_a = (10, 15, 30) shape_b = (20, 12, 4) np.random.seed(0) data_a = np.random.random(shape_a) data_b = np.random.random(shape_b) layer = Image(data_a) layer.dims.ndisplay = 3 layer.data = data_b assert np.all(layer.data == data_b) assert layer.ndim == len(shape_b) assert layer.shape == shape_b assert layer.dims.range == [(0, m, 1) for m in shape_b] assert layer._data_view.shape == shape_b[-3:]
def test_colormaps(): """Test setting test_colormaps.""" shapes = [(40, 20), (20, 10), (10, 5)] np.random.seed(0) data = [np.random.random(s) for s in shapes] layer = Image(data, multiscale=True) assert layer.colormap.name == 'gray' assert isinstance(layer.colormap, Colormap) layer.colormap = 'magma' assert layer.colormap.name == 'magma' assert isinstance(layer.colormap, Colormap) cmap = Colormap([[0.0, 0.0, 0.0, 0.0], [0.3, 0.7, 0.2, 1.0]]) layer.colormap = 'custom', cmap assert layer.colormap.name == 'custom' assert layer.colormap == cmap cmap = Colormap([[0.0, 0.0, 0.0, 0.0], [0.7, 0.2, 0.6, 1.0]]) layer.colormap = {'new': cmap} assert layer.colormap.name == 'new' assert layer.colormap == cmap layer = Image(data, multiscale=True, colormap='magma') assert layer.colormap.name == 'magma' assert isinstance(layer.colormap, Colormap) cmap = Colormap([[0.0, 0.0, 0.0, 0.0], [0.3, 0.7, 0.2, 1.0]]) layer = Image(data, multiscale=True, colormap=('custom', cmap)) assert layer.colormap.name == 'custom' assert layer.colormap == cmap cmap = Colormap([[0.0, 0.0, 0.0, 0.0], [0.7, 0.2, 0.6, 1.0]]) layer = Image(data, multiscale=True, colormap={'new': cmap}) assert layer.colormap.name == 'new' assert layer.colormap == cmap
def test_colormaps(): """Test setting test_colormaps.""" shapes = [(40, 20), (20, 10), (10, 5)] np.random.seed(0) data = [np.random.random(s) for s in shapes] layer = Image(data, is_pyramid=True) assert layer.colormap[0] == 'gray' assert type(layer.colormap[1]) == Colormap layer.colormap = 'magma' assert layer.colormap[0] == 'magma' assert type(layer.colormap[1]) == Colormap cmap = Colormap([[0.0, 0.0, 0.0, 0.0], [0.3, 0.7, 0.2, 1.0]]) layer.colormap = 'custom', cmap assert layer.colormap[0] == 'custom' assert layer.colormap[1] == cmap cmap = Colormap([[0.0, 0.0, 0.0, 0.0], [0.7, 0.2, 0.6, 1.0]]) layer.colormap = {'new': cmap} assert layer.colormap[0] == 'new' assert layer.colormap[1] == cmap layer = Image(data, is_pyramid=True, colormap='magma') assert layer.colormap[0] == 'magma' assert type(layer.colormap[1]) == Colormap cmap = Colormap([[0.0, 0.0, 0.0, 0.0], [0.3, 0.7, 0.2, 1.0]]) layer = Image(data, is_pyramid=True, colormap=('custom', cmap)) assert layer.colormap[0] == 'custom' assert layer.colormap[1] == cmap cmap = Colormap([[0.0, 0.0, 0.0, 0.0], [0.7, 0.2, 0.6, 1.0]]) layer = Image(data, is_pyramid=True, colormap={'new': cmap}) assert layer.colormap[0] == 'new' assert layer.colormap[1] == cmap
def test_scale(): """Test instantiating anisotropic 3D volume.""" shape = (10, 15, 20) scale = [3, 1, 1] full_shape = tuple(np.multiply(shape, scale)) np.random.seed(0) data = np.random.random(shape) layer = Image(data, scale=scale) layer.dims.ndisplay = 3 assert np.all(layer.data == data) assert layer.ndim == len(shape) assert layer.shape == full_shape # Note that the scale appears as the step size in the range assert layer.dims.range == list( (0, m, s) for m, s in zip(full_shape, scale)) assert layer._data_view.shape == shape[-3:]
def test_clim_slider_step_size_and_precision(qtbot, mag): """Make sure the slider has a reasonable step size and precision. ...across a broad range of orders of magnitude. """ layer = Image(np.random.rand(20, 20) / 10**mag) popup = create_range_popup(layer, 'contrast_limits') qtbot.addWidget(popup) # the range slider popup labels should have a number of decimal points that # is inversely proportional to the order of magnitude of the range of data, # but should never be greater than 5 or less than 0 assert popup.precision == max(min(mag + 3, 5), 0) # the slider step size should also be inversely proportional to the data # range, with 1000 steps across the data range assert np.ceil(popup.slider._step * 10**(mag + 4)) == 10
def test_changing_image_dims(): """Test changing Image data including dimensionality.""" shape_a = (10, 15) shape_b = (20, 12, 6) np.random.seed(0) data_a = np.random.random(shape_a) data_b = np.random.random(shape_b) layer = Image(data_a) # Prep indices for switch to 3D layer.data = data_b assert np.all(layer.data == data_b) assert layer.ndim == len(shape_b) np.testing.assert_array_equal(layer.extent.data[1], shape_b) assert layer.rgb is False assert layer._data_view.shape == shape_b[-2:]
def test_stack_to_images_multiscale(): """Test that a 3 channel multiscale image returns 3 multiscale images.""" data = list() data.append(np.random.randint(0, 200, (3, 128, 128))) data.append(np.random.randint(0, 200, (3, 64, 64))) data.append(np.random.randint(0, 200, (3, 32, 32))) data.append(np.random.randint(0, 200, (3, 16, 16))) stack = Image(data) images = stack_to_images(stack, 0) assert len(images) == 3 assert len(images[0].data) == 4 assert images[0].data[-1].shape[-1] == 16 assert images[1].data[-1].shape[-1] == 16 assert images[2].data[-1].shape[-1] == 16
def layers(): """Fixture that supplies a layers list for testing. Returns ------- napari.components.LayerList The desired napari LayerList. """ np.random.seed(0) list_of_layers = [ Image(np.random.rand(20, 20)), Labels(np.random.randint(10, size=(20, 2))), Points(np.random.rand(20, 2)), Shapes(np.random.rand(10, 2, 2)), Vectors(np.random.rand(10, 2, 2)), ] return LayerList(list_of_layers)
def test_changing_image_dims(): """Test changing Image data including dimensionality.""" shape_a = (10, 15) shape_b = (20, 12, 6) np.random.seed(0) data_a = np.random.random(shape_a) data_b = np.random.random(shape_b) layer = Image(data_a) # Prep indices for switch to 3D layer.data = data_b assert np.all(layer.data == data_b) assert layer.ndim == len(shape_b) assert layer.shape == shape_b assert layer.dims.range == [(0, m, 1) for m in shape_b] assert layer.rgb is False assert layer._data_view.shape == shape_b[-2:]
def test_depiction_combobox_changes(qtbot): """Changing the model attribute should update the view.""" layer = Image(np.random.rand(10, 15, 20)) layer._slice_dims(ndisplay=3) qtctrl = QtImageControls(layer) qtbot.addWidget(qtctrl) combo_box = qtctrl.depictionComboBox opts = {combo_box.itemText(i) for i in range(combo_box.count())} depiction_options = { 'volume', 'plane', } assert opts == depiction_options layer.depiction = 'plane' assert combo_box.findText('plane') == combo_box.currentIndex() layer.depiction = 'volume' assert combo_box.findText('volume') == combo_box.currentIndex()
def test_instantiate_with_experimental_clipping_planes_dict(): planes = [ { 'position': (0, 0, 0), 'normal': (0, 0, 1) }, { 'position': (0, 1, 0), 'normal': (1, 0, 0) }, ] image = Image(np.ones((32, 32, 32)), experimental_clipping_planes=planes) for i in range(len(planes)): assert (image.experimental_clipping_planes[i].position == planes[i] ['position']) assert (image.experimental_clipping_planes[i].normal == planes[i] ['normal'])
def test_images_to_stack_none_scale(): """Test combining images using scale & translate from 1st image in list""" images = [ Image( np.random.randint(0, 255, (10, 128, 128)), scale=(4, 1, 1), translate=(0, -1, 2), ) for _ in range(3) ] stack = images_to_stack(images, 1, colormap='green') assert isinstance(stack, Image) assert stack.data.shape == (10, 3, 128, 128) assert stack.colormap.name == 'green' assert list(stack.scale) == [4, 1, 1, 1] assert list(stack.translate) == [0, 0, -1, 2]
def test_clearing_layerlist(qtbot): """Test clearing layer list.""" layers = LayerList() view = QtLayerList(layers) qtbot.addWidget(view) layers.extend([Image(np.random.random((15, 15))) for _ in range(4)]) assert view.vbox_layout.count() == 2 * (len(layers) + 1) assert check_layout_layers(view.vbox_layout, layers) assert check_layout_dividers(view.vbox_layout, len(layers)) layers.clear() assert len(layers) == 0 assert view.vbox_layout.count() == 2 * (len(layers) + 1) assert check_layout_layers(view.vbox_layout, layers) assert check_layout_dividers(view.vbox_layout, len(layers))
def test_plane_controls_show_hide_on_ndisplay_change(qtbot): """Changing ndisplay should show/hide plane controls if depicting a plane.""" layer = Image(np.random.rand(10, 15, 20)) qtctrl = QtImageControls(layer) qtbot.addWidget(qtctrl) layer._slice_dims(ndisplay=3) layer.depiction = 'plane' assert not qtctrl.planeThicknessSlider.isHidden() assert not qtctrl.planeThicknessLabel.isHidden() assert not qtctrl.planeNormalButtons.isHidden() assert not qtctrl.planeNormalLabel.isHidden() layer._slice_dims(ndisplay=2) assert qtctrl.planeThicknessSlider.isHidden() assert qtctrl.planeThicknessLabel.isHidden() assert qtctrl.planeNormalButtons.isHidden() assert qtctrl.planeNormalLabel.isHidden()
def test_clim_slider_step_size_and_precision(qtbot, mag): """Make sure the slider has a reasonable step size and precision. ...across a broad range of orders of magnitude. """ layer = Image(np.random.rand(20, 20) * 10**mag) popup = QContrastLimitsPopup(layer) qtbot.addWidget(popup) # the range slider popup labels should have a number of decimal points that # is inversely proportional to the order of magnitude of the range of data, # but should never be greater than 5 or less than 0 decimals = min(6, max(int(3 - mag), 0)) assert popup.slider.decimals() == decimals # the slider step size should also be inversely proportional to the data # range, with 1000 steps across the data range assert popup.slider.singleStep() == 10**-decimals
def test_multiscale_tuple(): """Test instantiating Image layer multiscale tuple.""" shape = (40, 20) np.random.seed(0) img = np.random.random(shape) if skimage.__version__ > '0.19': pyramid_kwargs = {'channel_axis': None} else: pyramid_kwargs = {'multichannel': False} data = list(pyramid_gaussian(img, **pyramid_kwargs)) layer = Image(data) assert layer.data == data assert layer.multiscale is True assert layer.ndim == len(shape) np.testing.assert_array_equal(layer.extent.data[1], shape) assert layer.rgb is False assert layer._data_view.ndim == 2