def test_opacity(): """Test setting opacity.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) # Check default opacity value of 0.7 assert layer.opacity == 0.7 # Select data and change opacity of selection layer.selected_data = {0, 1} assert layer.opacity == 0.7 layer.opacity = 0.5 assert layer.opacity == 0.5 # Add new shape and test its width new_shape = np.random.random((1, 4, 2)) layer.selected_data = set() layer.add(new_shape) assert layer.opacity == 0.5 # Instantiate with custom opacity layer2 = Shapes(data, opacity=0.2) assert layer2.opacity == 0.2 # Check removing data shouldn't change opacity layer2.selected_data = {0, 2} layer2.remove_selected() assert len(layer2.data) == shape[0] - 2 assert layer2.opacity == 0.2
def test_text_from_property_fstring(properties): """Test setting text with an f-string from the property value""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data, properties=copy(properties), text='type: {shape_type}') expected_text = ['type: ' + v for v in properties['shape_type']] np.testing.assert_equal(layer.text.values, expected_text) # test updating the text layer.text = 'type-ish: {shape_type}' expected_text_2 = ['type-ish: ' + v for v in properties['shape_type']] np.testing.assert_equal(layer.text.values, expected_text_2) # copy/paste layer.selected_data = {0} layer._copy_data() layer._paste_data() expected_text_3 = expected_text_2 + ['type-ish: A'] np.testing.assert_equal(layer.text.values, expected_text_3) # add shape layer.selected_data = {0} new_shape = np.random.random((1, 4, 2)) layer.add(new_shape) expected_text_4 = expected_text_3 + ['type-ish: A'] np.testing.assert_equal(layer.text.values, expected_text_4)
def test_color_cycle(attribute, color_cycle): """Test setting edge/face color with a color cycle list""" # create Shapes using list color cycle shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) properties = {'shape_type': _make_cycled_properties(['A', 'B'], shape[0])} shapes_kwargs = { 'properties': properties, f'{attribute}_color': 'shape_type', f'{attribute}_color_cycle': color_cycle, } layer = Shapes(data, **shapes_kwargs) assert layer.properties == properties color_array = transform_color( list(islice(cycle(color_cycle), 0, shape[0])) ) layer_color = getattr(layer, f'{attribute}_color') np.testing.assert_allclose(layer_color, color_array) # Add new shape and test its color new_shape = np.random.random((1, 4, 2)) layer.selected_data = {0} layer.add(new_shape) layer_color = getattr(layer, f'{attribute}_color') assert len(layer_color) == shape[0] + 1 np.testing.assert_allclose( layer_color, np.vstack((color_array, transform_color('red'))), ) # Check removing data adjusts colors correctly layer.selected_data = {0, 2} layer.remove_selected() assert len(layer.data) == shape[0] - 1 layer_color = getattr(layer, f'{attribute}_color') assert len(layer_color) == shape[0] - 1 np.testing.assert_allclose( layer_color, np.vstack((color_array[1], color_array[3:], transform_color('red'))), ) # refresh colors layer.refresh_colors(update_color_mapping=True) # test adding a shape with a new property value layer.selected_data = {} current_properties = layer.current_properties current_properties['shape_type'] = np.array(['new']) layer.current_properties = current_properties new_shape_2 = np.random.random((1, 4, 2)) layer.add(new_shape_2) color_cycle_map = getattr(layer, f'{attribute}_color_cycle_map') assert 'new' in color_cycle_map np.testing.assert_allclose( color_cycle_map['new'], np.squeeze(transform_color(color_cycle[0])) )
def test_color_direct(attribute: str): """Test setting face/edge color directly.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer_kwargs = {f'{attribute}_color': 'black'} layer = Shapes(data, **layer_kwargs) color_array = transform_color(['black'] * shape[0]) current_color = getattr(layer, f'current_{attribute}_color') layer_color = getattr(layer, f'{attribute}_color') assert current_color == 'black' assert len(layer.edge_color) == shape[0] np.testing.assert_allclose(color_array, layer_color) # With no data selected changing color has no effect setattr(layer, f'current_{attribute}_color', 'blue') current_color = getattr(layer, f'current_{attribute}_color') assert current_color == 'blue' np.testing.assert_allclose(color_array, layer_color) # Select data and change edge color of selection selected_data = {0, 1} layer.selected_data = {0, 1} current_color = getattr(layer, f'current_{attribute}_color') assert current_color == 'black' setattr(layer, f'current_{attribute}_color', 'green') colorarray_green = transform_color(['green'] * len(layer.selected_data)) color_array[list(selected_data)] = colorarray_green layer_color = getattr(layer, f'{attribute}_color') np.testing.assert_allclose(color_array, layer_color) # Add new shape and test its color new_shape = np.random.random((1, 4, 2)) layer.selected_data = set() setattr(layer, f'current_{attribute}_color', 'blue') layer.add(new_shape) color_array = np.vstack([color_array, transform_color('blue')]) layer_color = getattr(layer, f'{attribute}_color') assert len(layer_color) == shape[0] + 1 np.testing.assert_allclose(color_array, layer_color) # Check removing data adjusts colors correctly layer.selected_data = {0, 2} layer.remove_selected() assert len(layer.data) == shape[0] - 1 layer_color = getattr(layer, f'{attribute}_color') assert len(layer_color) == shape[0] - 1 np.testing.assert_allclose( layer_color, np.vstack((color_array[1], color_array[3:])), ) # set the color directly setattr(layer, f'{attribute}_color', 'black') color_array = np.tile([[0, 0, 0, 1]], (len(layer.data), 1)) layer_color = getattr(layer, f'{attribute}_color') np.testing.assert_allclose(color_array, layer_color)
def test_face_color(): """Test setting face color.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) assert layer.face_color == 'white' assert len(layer.face_colors) == shape[0] assert layer.face_colors == ['white'] * shape[0] # With no data selected chaning face color has no effect layer.face_color = 'blue' assert layer.face_color == 'blue' assert layer.face_colors == ['white'] * shape[0] # Select data and change face color of selection layer.selected_data = [0, 1] assert layer.face_color == 'white' layer.face_color = 'green' assert layer.face_colors == ['green'] * 2 + ['white'] * (shape[0] - 2) # Add new shape and test its color new_shape = np.random.random((1, 4, 2)) layer.selected_data = [] layer.face_color = 'blue' layer.add(new_shape) assert len(layer.face_colors) == shape[0] + 1 assert layer.face_colors == ['green'] * 2 + ['white'] * (shape[0] - 2) + [ 'blue' ] # Instantiate with custom face color layer = Shapes(data, face_color='red') assert layer.face_color == 'red' # Instantiate with custom face color list col_list = ['red', 'green'] * 5 layer = Shapes(data, face_color=col_list) assert layer.face_color == 'white' assert layer.face_colors == col_list # Add new point and test its color layer.face_color = 'blue' layer.add(new_shape) assert len(layer.face_colors) == shape[0] + 1 assert layer.face_colors == col_list + ['blue'] # Check removing data adjusts colors correctly layer.selected_data = [0, 2] layer.remove_selected() assert len(layer.data) == shape[0] - 1 assert len(layer.face_colors) == shape[0] - 1 assert layer.face_colors == [col_list[1]] + col_list[3:] + ['blue']
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_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_opacities(): """Test setting opacities.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) # Check default opacity value of 0.7 assert layer.opacity == 0.7 assert len(layer.opacities) == shape[0] assert layer.opacities == [0.7] * shape[0] # With no data selected chaning opacity has no effect layer.opacity = 1 assert layer.opacity == 1 assert layer.opacities == [0.7] * shape[0] # Select data and change opacity of selection layer.selected_data = [0, 1] assert layer.opacity == 0.7 layer.opacity = 0.5 assert layer.opacities == [0.5] * 2 + [0.7] * (shape[0] - 2) # Add new shape and test its width new_shape = np.random.random((1, 4, 2)) layer.selected_data = [] layer.opacity = 0.3 layer.add(new_shape) assert layer.opacities == [0.5] * 2 + [0.7] * (shape[0] - 2) + [0.3] # Instantiate with custom opacity layer = Shapes(data, opacity=0.2) assert layer.opacity == 0.2 # Instantiate with custom opacity list opacity_list = [0.1, 0.4] * 5 layer = Shapes(data, opacity=opacity_list) assert layer.opacity == 0.7 assert layer.opacities == opacity_list # Add new shape and test its opacity layer.opacity = 0.6 layer.add(new_shape) assert len(layer.opacities) == shape[0] + 1 assert layer.opacities == opacity_list + [0.6] # Check removing data adjusts opacities correctly layer.selected_data = [0, 2] layer.remove_selected() assert len(layer.data) == shape[0] - 1 assert len(layer.opacities) == shape[0] - 1 assert layer.opacities == [opacity_list[1]] + opacity_list[3:] + [0.6]
def test_edge_width(): """Test setting edge width.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) assert layer.edge_width == 1 assert len(layer.edge_widths) == shape[0] assert layer.edge_widths == [1] * shape[0] # With no data selected chaning edge width has no effect layer.edge_width = 2 assert layer.edge_width == 2 assert layer.edge_widths == [1] * shape[0] # Select data and change edge color of selection layer.selected_data = [0, 1] assert layer.edge_width == 1 layer.edge_width = 3 assert layer.edge_widths == [3] * 2 + [1] * (shape[0] - 2) # Add new shape and test its width new_shape = np.random.random((1, 4, 2)) layer.selected_data = [] layer.edge_width = 4 layer.add(new_shape) assert layer.edge_widths == [3] * 2 + [1] * (shape[0] - 2) + [4] # Instantiate with custom edge width layer = Shapes(data, edge_width=5) assert layer.edge_width == 5 # Instantiate with custom edge width list width_list = [2, 3] * 5 layer = Shapes(data, edge_width=width_list) assert layer.edge_width == 1 assert layer.edge_widths == width_list # Add new shape and test its color layer.edge_width = 4 layer.add(new_shape) assert len(layer.edge_widths) == shape[0] + 1 assert layer.edge_widths == width_list + [4] # Check removing data adjusts colors correctly layer.selected_data = [0, 2] layer.remove_selected() assert len(layer.data) == shape[0] - 1 assert len(layer.edge_widths) == shape[0] - 1 assert layer.edge_widths == [width_list[1]] + width_list[3:] + [4]
def test_removing_selected_shapes(): """Test removing selected shapes.""" 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) # With nothing selected no points should be removed layer.remove_selected() assert len(layer.data) == len(data) # Select three shapes and remove them layer.selected_data = [1, 7, 8] layer.remove_selected() keep = [0] + list(range(2, 7)) + [9] data_keep = [data[i] for i in keep] shape_type_keep = [shape_type[i] for i in keep] assert len(layer.data) == len(data_keep) assert len(layer.selected_data) == 0 assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data_keep)]) assert layer.ndim == 2 assert np.all( [s == so for s, so in zip(layer.shape_types, shape_type_keep)])
def test_z_index(): """Test setting z-index during instantiation.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) layer = Shapes(data) assert layer.z_indices == [0] * shape[0] # Instantiate with custom z-index layer = Shapes(data, z_index=4) assert layer.z_indices == [4] * shape[0] # Instantiate with custom z-index list z_index_list = [2, 3] * 5 layer = Shapes(data, z_index=z_index_list) assert layer.z_indices == z_index_list # Add new shape and its z-index new_shape = np.random.random((1, 4, 2)) layer.add(new_shape) assert len(layer.z_indices) == shape[0] + 1 assert layer.z_indices == z_index_list + [4] # Check removing data adjusts colors correctly layer.selected_data = [0, 2] layer.remove_selected() assert len(layer.data) == shape[0] - 1 assert len(layer.z_indices) == shape[0] - 1 assert layer.z_indices == [z_index_list[1]] + z_index_list[3:] + [4]
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_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_delete(): # Test on three four corner rectangle layer = Shapes(20 * np.random.random((3, 4, 2))) layer.mode = 'direct' assert len(layer.data) == 3 layer.selected_data = {0, 1} key_bindings.delete_selected(layer) assert len(layer.data) == 1
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_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_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_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_value(): """Test getting the value of the data at the current coordinates.""" shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) data[-1, :] = [[0, 0], [0, 10], [10, 0], [10, 10]] layer = Shapes(data) value = layer.get_value((0, 0)) assert value == (9, None) layer.mode = 'select' layer.selected_data = [9] value = layer.get_value((0, 0)) assert value == (9, 7) layer = Shapes(data + 5) value = layer.get_value((0, 0)) assert value == (None, None)
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 test_color_colormap(attribute): """Test setting edge/face color with a colormap""" # create Shapes using with a colormap shape = (10, 4, 2) np.random.seed(0) data = 20 * np.random.random(shape) properties = {'shape_type': _make_cycled_properties([0, 1.5], shape[0])} shapes_kwargs = { 'properties': properties, f'{attribute}_color': 'shape_type', f'{attribute}_colormap': 'gray', } layer = Shapes(data, **shapes_kwargs) assert layer.properties == properties color_mode = getattr(layer, f'{attribute}_color_mode') assert color_mode == 'colormap' color_array = transform_color(['black', 'white'] * int((shape[0] / 2))) attribute_color = getattr(layer, f'{attribute}_color') assert np.all(attribute_color == color_array) # change the color cycle - face_color should not change setattr(layer, f'{attribute}_color_cycle', ['red', 'blue']) attribute_color = getattr(layer, f'{attribute}_color') assert np.all(attribute_color == color_array) # Add new shape and test its color new_shape = np.random.random((1, 4, 2)) layer.selected_data = {0} layer.add(new_shape) attribute_color = getattr(layer, f'{attribute}_color') assert len(attribute_color) == shape[0] + 1 np.testing.assert_allclose( attribute_color, np.vstack((color_array, transform_color('black'))), ) # Check removing data adjusts colors correctly layer.selected_data = {0, 2} layer.remove_selected() assert len(layer.data) == shape[0] - 1 attribute_color = getattr(layer, f'{attribute}_color') assert len(attribute_color) == shape[0] - 1 np.testing.assert_allclose( attribute_color, np.vstack(( color_array[1], color_array[3:], transform_color('black'), )), ) # adjust the clims setattr(layer, f'{attribute}_contrast_limits', (0, 3)) layer.refresh_colors(update_color_mapping=False) attribute_color = getattr(layer, f'{attribute}_color') np.testing.assert_allclose(attribute_color[-2], [0.5, 0.5, 0.5, 1]) # change the colormap new_colormap = 'viridis' setattr(layer, f'{attribute}_colormap', new_colormap) attribute_colormap = getattr(layer, f'{attribute}_colormap') assert attribute_colormap[1] == get_colormap(new_colormap)