def test_to_labels_3D(): """Test label generation for 3D data""" data = [ [[0, 100, 100], [0, 100, 200], [0, 200, 200], [0, 200, 100]], [[1, 125, 125], [1, 125, 175], [1, 175, 175], [1, 175, 125]], [[2, 100, 100], [2, 100, 200], [2, 200, 200], [2, 200, 100]], ] labels_shape = (3, 300, 300) layer = Shapes(np.array(data), shape_type='polygon') labels = layer.to_labels(labels_shape=labels_shape) assert np.all(labels.shape == labels_shape) assert np.all(np.unique(labels) == [0, 1, 2, 3])
def test_polygons(): """Test instantiating Shapes layer with a random 2D polygons.""" # Test a single polygon with 6 points shape = (1, 6, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data, shape_type='polygon') assert layer.nshapes == shape[0] assert np.all(layer.data[0] == data[0]) assert layer.ndim == shape[2] assert np.all([s == 'polygon' for s in layer.shape_type]) # Test multiple polygons with different numbers of points data = [ 20 * np.random.random((np.random.randint(2, 12), 2)) for i in range(10) ] layer = Shapes(data, shape_type='polygon') assert layer.nshapes == len(data) assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data)]) assert layer.ndim == 2 assert np.all([s == 'polygon' for s in layer.shape_type])
def test_to_masks(): """Test the mask generation.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) masks = layer.to_masks() assert masks.ndim == 3 assert len(masks) == shape[0] masks = layer.to_masks(mask_shape=[20, 20]) assert masks.shape == (shape[0], 20, 20)
def test_lines(): """Test instantiating Shapes layer with a random 2D lines.""" # Test a single two end point line shape = (1, 2, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data, shape_type='line') assert layer.nshapes == shape[0] assert np.all(layer.data[0] == data[0]) assert layer.ndim == shape[2] assert np.all([s == 'line' for s in layer.shape_type]) # Test multiple lines shape = (10, 2, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data, shape_type='line') assert layer.nshapes == shape[0] assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data)]) assert layer.ndim == shape[2] assert np.all([s == 'line' for s in layer.shape_type])
def test_to_labels(): """Test the labels generation.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) labels = layer.to_labels() assert labels.ndim == 2 assert len(np.unique(labels)) <= 11 labels = layer.to_labels(labels_shape=[20, 20]) assert labels.shape == (20, 20) assert len(np.unique(labels)) <= 11
def test_mixed_shapes(): """Test instantiating Shapes layer with a mix of random 2D shapes.""" # Test multiple polygons with different numbers of points np.random.seed(0) data = [ 20 * np.random.random((np.random.randint(2, 12), 2)) for i in range(5) ] + list(np.random.random((5, 4, 2))) shape_type = ['polygon'] * 5 + ['rectangle'] * 3 + ['ellipse'] * 2 layer = Shapes(data, shape_type=shape_type) assert layer.nshapes == len(data) assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data)]) assert layer.ndim == 2 assert np.all([s == so for s, so in zip(layer.shape_type, shape_type)]) # Test roundtrip with mixed data new_layer = Shapes(layer.data, shape_type=layer.shape_type) assert np.all( [np.all(nd == d) for nd, d in zip(new_layer.data, layer.data)] ) assert np.all( [ns == s for ns, s in zip(new_layer.shape_type, layer.shape_type)] )
def test_remove_selected_with_derived_text(): """See https://github.com/napari/napari/issues/3504""" shapes = np.random.rand(3, 4, 2) properties = {'class': np.array(['A', 'B', 'C'])} layer = Shapes(shapes, properties=properties, text='class') vispy_layer = VispyShapesLayer(layer) text_node = vispy_layer._get_text_node() np.testing.assert_array_equal(text_node.text, ['A', 'B', 'C']) layer.selected_data = {1} layer.remove_selected() np.testing.assert_array_equal(text_node.text, ['A', 'C'])
def test_changing_shapes(): """Test changing Shapes data.""" shape_a = (10, 4, 2) shape_b = (20, 4, 2) np.random.seed(0) data_a = 20 * np.random.random(shape_a) data_b = 20 * np.random.random(shape_b) layer = Shapes(data_a) layer.data = data_b assert layer.nshapes == shape_b[0] assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data_b)]) assert layer.ndim == shape_b[2] assert np.all([s == 'rectangle' for s in layer.shape_types])
def test_selecting_shapes(): """Test selecting shapes.""" data = 20 * np.random.random((10, 4, 2)) np.random.seed(0) layer = Shapes(data) layer.selected_data = [0, 1] assert layer.selected_data == [0, 1] layer.selected_data = [9] assert layer.selected_data == [9] layer.selected_data = [] assert layer.selected_data == []
def test_rectangles(): """Test instantiating Shapes layer with a random 2D rectangles.""" # Test a single four corner rectangle shape = (1, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) assert layer.nshapes == shape[0] assert np.all(layer.data[0] == data[0]) assert layer.ndim == shape[2] assert np.all([s == 'rectangle' for s in layer.shape_types]) # Test multiple four corner rectangles shape = (10, 4, 2) data = 20 * np.random.random(shape) layer = Shapes(data) assert layer.nshapes == shape[0] assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data)]) assert layer.ndim == shape[2] assert np.all([s == 'rectangle' for s in layer.shape_types]) # Test a single two corner rectangle, which gets converted into four # corner rectangle shape = (1, 2, 2) data = 20 * np.random.random(shape) layer = Shapes(data) assert layer.nshapes == 1 assert len(layer.data[0]) == 4 assert layer.ndim == shape[2] assert np.all([s == 'rectangle' for s in layer.shape_types]) # Test multiple two corner rectangles shape = (10, 2, 2) data = 20 * np.random.random(shape) layer = Shapes(data) assert layer.nshapes == shape[0] assert np.all([len(ld) == 4 for ld in layer.data]) assert layer.ndim == shape[2] assert np.all([s == 'rectangle' for s in layer.shape_types])
def test_move_to_back(): """Test moving shapes to back.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) z_index_list = [2, 3] * 5 layer = Shapes(data, z_index=z_index_list) assert layer.z_indices == z_index_list # Move selected shapes to front layer.selected_data = [0, 2] layer.move_to_back() assert layer.z_indices == [1] + [z_index_list[1]] + [1] + z_index_list[3:]
def test_selecting_shapes(): """Test selecting shapes.""" data = 20 * np.random.random((10, 4, 2)) np.random.seed(0) layer = Shapes(data) layer.selected_data = {0, 1} assert layer.selected_data == {0, 1} layer.selected_data = {9} assert layer.selected_data == {9} layer.selected_data = set() assert layer.selected_data == set()
def test_add_colormap(attribute): """Test directly adding a vispy Colormap object""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) annotations = {'shape_type': _make_cycled_properties([0, 1.5], shape[0])} color_kwarg = f'{attribute}_color' colormap_kwarg = f'{attribute}_colormap' args = {color_kwarg: 'shape_type', colormap_kwarg: 'viridis'} layer = Shapes(data, properties=annotations, **args) setattr(layer, f'{attribute}_colormap', get_colormap('gray')) layer_colormap = getattr(layer, f'{attribute}_colormap') assert 'unnamed colormap' in layer_colormap[0]
def test_change_text_updates_node_string(): shapes = np.random.rand(3, 4, 2) properties = { 'class': np.array(['A', 'B', 'C']), 'name': np.array(['D', 'E', 'F']), } layer = Shapes(shapes, properties=properties, text='class') vispy_layer = VispyShapesLayer(layer) text_node = vispy_layer._get_text_node() np.testing.assert_array_equal(text_node.text, properties['class']) layer.text = 'name' np.testing.assert_array_equal(text_node.text, properties['name'])
def test_message(): """Test converting values and coords to message.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) msg = layer.get_message(layer.coordinates, 3, 2) assert type(msg) == str msg = layer.get_message(layer.coordinates, 4, None) assert type(msg) == str msg = layer.get_message(layer.coordinates, None, None) assert type(msg) == str
def test_add_single_shape_consistent_properties(): """Test adding a single shape ensures correct number of added properties""" data = [ np.array([[100, 200], [200, 300]]), np.array([[300, 400], [400, 500]]), ] properties = {'index': [1, 2]} layer = Shapes(np.array(data), shape_type='rectangle', properties=properties) layer.add(np.array([[500, 600], [700, 800]])) assert len(layer.properties['index']) == 3 assert layer.properties['index'][2] == 2
def test_4D_ellispse(): """Test instantiating Shapes layer with 4D planar ellipse.""" # Test a single 4D ellipse np.random.seed(0) data = [[ [3, 5, 108, 108], [3, 5, 108, 148], [3, 5, 148, 148], [3, 5, 148, 108], ]] layer = Shapes(data, shape_type='ellipse') assert layer.nshapes == len(data) assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data)]) assert layer.ndim == 4 assert np.all([s == 'ellipse' for s in layer.shape_type])
def test_copy_paste(): # Test on three four corner rectangle layer = Shapes(20 * np.random.random((3, 4, 2))) layer.mode = 'direct' assert len(layer.data) == 3 assert layer._clipboard == {} layer.selected_data = {0, 1} key_bindings.copy(layer) assert len(layer.data) == 3 assert len(layer._clipboard) == 5 key_bindings.paste(layer) assert len(layer.data) == 5 assert len(layer._clipboard) == 5
def test_interaction_box(): """Test the creation of the interaction box.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) assert layer._selected_box == None layer.selected_data = [0] assert len(layer._selected_box) == 10 layer.selected_data = [0, 1] assert len(layer._selected_box) == 10 layer.selected_data = [] assert layer._selected_box == None
def test_changing_modes(): """Test changing modes.""" np.random.seed(0) data = 20 * np.random.random((10, 4, 2)) layer = Shapes(data) assert layer.mode == 'pan_zoom' assert layer.interactive == True layer.mode = 'select' assert layer.mode == 'select' assert layer.interactive == False layer.mode = 'direct' assert layer.mode == 'direct' assert layer.interactive == False layer.mode = 'vertex_insert' assert layer.mode == 'vertex_insert' assert layer.interactive == False layer.mode = 'vertex_remove' assert layer.mode == 'vertex_remove' assert layer.interactive == False layer.mode = 'add_rectangle' assert layer.mode == 'add_rectangle' assert layer.interactive == False layer.mode = 'add_ellipse' assert layer.mode == 'add_ellipse' assert layer.interactive == False layer.mode = 'add_line' assert layer.mode == 'add_line' assert layer.interactive == False layer.mode = 'add_path' assert layer.mode == 'add_path' assert layer.interactive == False layer.mode = 'add_polygon' assert layer.mode == 'add_polygon' assert layer.interactive == False layer.mode = 'pan_zoom' assert layer.mode == 'pan_zoom' assert layer.interactive == True
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_properties(properties): shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data, properties=copy(properties)) np.testing.assert_equal(layer.properties, properties) current_prop = {'shape_type': np.array(['B'])} assert layer.current_properties == current_prop # test removing shapes layer.selected_data = {0, 1} layer.remove_selected() remove_properties = properties['shape_type'][2::] assert len(layer.properties['shape_type']) == (shape[0] - 2) assert np.all(layer.properties['shape_type'] == remove_properties) # test selection of properties layer.selected_data = {0} selected_annotation = layer.current_properties['shape_type'] assert len(selected_annotation) == 1 assert selected_annotation[0] == 'A' # test adding shapes with properties new_data = np.random.random((1, 4, 2)) new_shape_type = ['rectangle'] layer.add(new_data, shape_type=new_shape_type) add_properties = np.concatenate((remove_properties, ['A']), axis=0) assert np.all(layer.properties['shape_type'] == add_properties) # test copy/paste layer.selected_data = {0, 1} layer._copy_data() assert np.all(layer._clipboard['properties']['shape_type'] == ['A', 'B']) layer._paste_data() paste_properties = np.concatenate((add_properties, ['A', 'B']), axis=0) assert np.all(layer.properties['shape_type'] == paste_properties) # test updating a property layer.mode = 'select' layer.selected_data = {0} new_property = {'shape_type': np.array(['B'])} layer.current_properties = new_property updated_properties = layer.properties assert updated_properties['shape_type'][0] == 'B'
def test_adding_shapes_to_empty(): """Test adding shapes to empty.""" data = np.empty((0, 0, 2)) np.random.seed(0) layer = Shapes(np.empty((0, 0, 2))) assert len(layer.data) == 0 data = [ 20 * np.random.random((np.random.randint(2, 12), 2)) for i in range(5) ] + list(np.random.random((5, 4, 2))) shape_type = ['path'] * 5 + ['rectangle'] * 3 + ['ellipse'] * 2 layer.add(data, shape_type=shape_type) assert layer.nshapes == len(data) assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data)]) assert layer.ndim == 2 assert np.all([s == so for s, so in zip(layer.shape_types, shape_type)])
def test_adding_shapes(): """Test adding shapes.""" # Start with polygons with different numbers of points np.random.seed(0) data = [ 20 * np.random.random((np.random.randint(2, 12), 2)) for i in range(5) ] # shape_type = ['polygon'] * 5 + ['rectangle'] * 3 + ['ellipse'] * 2 layer = Shapes(data, shape_type='polygon') new_data = np.random.random((5, 4, 2)) new_shape_type = ['rectangle'] * 3 + ['ellipse'] * 2 layer.add(new_data, shape_type=new_shape_type) all_data = data + list(new_data) all_shape_type = ['polygon'] * 5 + new_shape_type assert layer.nshapes == len(all_data) assert np.all([np.all(ld == d) for ld, d in zip(layer.data, all_data)]) assert layer.ndim == 2 assert np.all([s == so for s, so in zip(layer.shape_type, all_shape_type)])
def test_copy_and_paste(): """Test copying and pasting selected shapes.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) # Clipboard starts empty assert layer._clipboard == {} # Pasting empty clipboard doesn't change data layer._paste_data() assert len(layer.data) == 10 # Copying with nothing selected leave clipboard empty layer._copy_data() assert layer._clipboard == {} # Copying and pasting with two shapes selected adds to clipboard and data layer.selected_data = {0, 1} layer._copy_data() layer._paste_data() assert len(layer._clipboard) == 2 assert len(layer.data) == shape[0] + 2 assert np.all( [np.all(a == b) for a, b in zip(layer.data[:2], layer.data[-2:])] ) # Pasting again adds two more points to data layer._paste_data() assert len(layer.data) == shape[0] + 4 assert np.all( [np.all(a == b) for a, b in zip(layer.data[:2], layer.data[-2:])] ) # Unselecting everything and copying and pasting will empty the clipboard # and add no new data layer.selected_data = set() layer._copy_data() layer._paste_data() assert layer._clipboard == {} assert len(layer.data) == shape[0] + 4
def test_add_color_cycle_to_empty_layer(attribute): """ Test adding a shape to an empty layer when edge/face color is a color cycle See: https://github.com/napari/napari/pull/1069 """ default_properties = {'shape_type': np.array(['A'])} color_cycle = ['red', 'blue'] shapes_kwargs = { 'properties': default_properties, f'{attribute}_color': 'shape_type', f'{attribute}_color_cycle': color_cycle, } layer = Shapes(**shapes_kwargs) # verify the current_edge_color is correct expected_color = transform_color(color_cycle[0]) current_color = getattr(layer, f'_current_{attribute}_color') np.testing.assert_allclose(current_color, expected_color) # add a shape np.random.seed(0) new_shape = 20 * np.random.random((1, 4, 2)) layer.add(new_shape) props = {'shape_type': np.array(['A'])} expected_color = np.array([[1, 0, 0, 1]]) np.testing.assert_equal(layer.properties, props) attribute_color = getattr(layer, f'{attribute}_color') np.testing.assert_allclose(attribute_color, expected_color) # add a shape with a new property layer.selected_data = [] layer.current_properties = {'shape_type': np.array(['B'])} new_shape_2 = 20 * np.random.random((1, 4, 2)) layer.add(new_shape_2) new_color = np.array([0, 0, 1, 1]) expected_color = np.vstack((expected_color, new_color)) new_properties = {'shape_type': np.array(['A', 'B'])} attribute_color = getattr(layer, f'{attribute}_color') np.testing.assert_allclose(attribute_color, expected_color) np.testing.assert_equal(layer.properties, new_properties)
def setup(self, n): np.random.seed(0) self.data = [50 * np.random.random((6, 2)) for i in range(n)] self.layer = Shapes(self.data, shape_type='polygon') self.layer.mode = 'select' # create events self.click_event = ReadOnlyWrapper( Event(type='mouse_press', is_dragging=False, modifiers=[])) self.release_event = ReadOnlyWrapper( Event(type='mouse_release', is_dragging=False, modifiers=[])) self.drag_event = ReadOnlyWrapper( Event(type='mouse_move', is_dragging=True, modifiers=[])) # initialize the position and select a shape self.layer.position = tuple(np.mean(self.layer.data[0], axis=0)) # Simulate click mouse_press_callbacks(self.layer, self.click_event) # Simulate release mouse_release_callbacks(self.layer, self.release_event)
def test_set_text_with_kwarg_dict(properties): text_kwargs = { 'text': 'type: {shape_type}', 'color': [0, 0, 0, 1], 'rotation': 10, 'translation': [5, 5], 'anchor': 'upper_left', 'size': 10, 'visible': True, } shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data, properties=copy(properties), text=text_kwargs) expected_text = ['type: ' + v for v in properties['shape_type']] np.testing.assert_equal(layer.text.values, expected_text) for property, value in text_kwargs.items(): if property == 'text': continue layer_value = getattr(layer._text, property) np.testing.assert_equal(layer_value, value)
def create_known_shapes_layer(): """Create shapes layer with known coordinates Returns ------- layer : napari.layers.Shapes Shapes layer. n_shapes : int Number of shapes in the shapes layer known_non_shape : list Data coordinates that are known to contain no shapes. Useful during testing when needing to guarantee no shape is clicked on. """ data = [[[1, 3], [8, 4]], [[10, 10], [15, 4]]] known_non_shape = [20, 30] n_shapes = len(data) layer = Shapes(data) assert layer.ndim == 2 assert len(layer.data) == n_shapes assert len(layer.selected_data) == 0 return layer, n_shapes, known_non_shape
def test_activate_modes(): # Test a single four corner rectangle layer = Shapes(20 * np.random.random((1, 4, 2))) # need to go through the generator key_bindings.activate_add_rectangle_mode(layer) assert layer.mode == 'add_rectangle' key_bindings.activate_add_ellipse_mode(layer) assert layer.mode == 'add_ellipse' key_bindings.activate_add_line_mode(layer) assert layer.mode == 'add_line' key_bindings.activate_add_path_mode(layer) assert layer.mode == 'add_path' key_bindings.activate_add_polygon_mode(layer) assert layer.mode == 'add_polygon' key_bindings.activate_direct_mode(layer) assert layer.mode == 'direct' key_bindings.activate_select_mode(layer) assert layer.mode == 'select' key_bindings.activate_pan_zoom_mode(layer) assert layer.mode == 'pan_zoom' key_bindings.activate_vertex_insert_mode(layer) assert layer.mode == 'vertex_insert' key_bindings.activate_vertex_remove_mode(layer) assert layer.mode == 'vertex_remove'