Esempio n. 1
0
def layer(request):
    """Parameterized fixture that supplies a layer for testing.

    Parameters
    ----------
    request : _pytest.fixtures.SubRequest
        The pytest request object

    Returns
    -------
    napari.layers.Layer
        The desired napari Layer.
    """
    np.random.seed(0)
    if request.param == 'image':
        data = np.random.rand(20, 20)
        return Image(data)
    elif request.param == 'labels':
        data = np.random.randint(10, size=(20, 20))
        return Labels(data)
    elif request.param == 'points':
        data = np.random.rand(20, 2)
        return Points(data)
    elif request.param == 'shapes':
        data = [
            np.random.rand(2, 2),
            np.random.rand(2, 2),
            np.random.rand(6, 2),
            np.random.rand(6, 2),
            np.random.rand(2, 2),
        ]
        shape_type = ['ellipse', 'line', 'path', 'polygon', 'rectangle']
        return Shapes(data, shape_type=shape_type)
    elif request.param == 'shapes-rectangles':
        data = np.random.rand(7, 4, 2)
        return Shapes(data)
    elif request.param == 'vectors':
        data = np.random.rand(20, 2, 2)
        return Vectors(data)
    else:
        return None
Esempio n. 2
0
def test_3D_rectangles():
    """Test instantiating Shapes layer with 3D planar rectangles."""
    # Test a single four corner rectangle
    np.random.seed(0)
    planes = np.tile(np.arange(10).reshape((10, 1, 1)), (1, 4, 1))
    corners = np.random.uniform(0, 10, size=(10, 4, 2))
    data = np.concatenate((planes, corners), axis=2)
    layer = Shapes(data)
    assert layer.nshapes == len(data)
    assert np.all([np.all(ld == d) for ld, d in zip(layer.data, data)])
    assert layer.ndim == 3
    assert np.all([s == 'rectangle' for s in layer.shape_types])
Esempio n. 3
0
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_types])

    # 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_types])
Esempio n. 4
0
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_types])

    # 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_types])
Esempio n. 5
0
def test_change_text_color_updates_node_color():
    shapes = np.random.rand(3, 4, 2)
    properties = {'class': np.array(['A', 'B', 'C'])}
    text = {'string': 'class', 'color': [1, 0, 0]}
    layer = Shapes(shapes, properties=properties, text=text)
    vispy_layer = VispyShapesLayer(layer)
    text_node = vispy_layer._get_text_node()
    np.testing.assert_array_equal(text_node.color.rgb, [[1, 0, 0]])

    layer.text.color = [0, 0, 1]

    np.testing.assert_array_equal(text_node.color.rgb, [[0, 0, 1]])
def layer_data_and_types():
    np.random.seed(0)
    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)),
    ]
    layer_data = [l.as_layer_data_tuple() for l in layers]
    layer_types = [ld[2] for ld in layer_data]
    return layer_data, layer_types
Esempio n. 7
0
class Shapes2DSuite:
    """Benchmarks for the Shapes layer with 2D data"""

    params = [2**i for i in range(4, 9)]

    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')

    def time_create_layer(self, n):
        """Time to create an image layer."""
        layer = Shapes(self.data, shape_type='polygon')

    def time_set_view_slice(self, n):
        """Time to set view slice."""
        self.layer._set_view_slice()

    def time_update_thumbnail(self, n):
        """Time to update thumbnail."""
        self.layer._update_thumbnail()

    def time_get_value(self, n):
        """Time to get current value."""
        self.layer.get_value()

    def mem_layer(self, n):
        """Memory used by layer."""
        return self.layer

    def mem_data(self, n):
        """Memory used by raw data."""
        return self.data
Esempio n. 8
0
def test_adding_properties(attribute):
    """Test adding properties to an existing layer"""
    shape = (10, 4, 2)
    np.random.seed(0)
    data = 20 * np.random.random(shape)
    layer = Shapes(data)

    # add properties
    properties = {'shape_type': _make_cycled_properties(['A', 'B'], shape[0])}
    layer.properties = properties
    np.testing.assert_equal(layer.properties, properties)

    # add properties as a dataframe
    properties_df = pd.DataFrame(properties)
    layer.properties = properties_df
    np.testing.assert_equal(layer.properties, properties)

    # add properties as a dictionary with list values
    properties_list = {
        'shape_type': list(_make_cycled_properties(['A', 'B'], shape[0]))
    }
    layer.properties = properties_list
    assert isinstance(layer.properties['shape_type'], np.ndarray)

    # removing a property that was the _*_color_property should give a warning
    setattr(layer, f'_{attribute}_color_property', 'shape_type')
    properties_2 = {
        'not_shape_type': _make_cycled_properties(['A', 'B'], shape[0])
    }
    with pytest.warns(RuntimeWarning):
        layer.properties = properties_2
Esempio n. 9
0
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)
Esempio n. 10
0
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])
Esempio n. 11
0
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)]
    )
Esempio n. 12
0
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]
Esempio n. 13
0
def test_lock_aspect_ratio_selected_box_zeros():
    # Test a single four corner rectangle that has zero size
    layer = Shapes(20 * np.zeros((1, 4, 2)))
    # select a shape
    layer._selected_box = layer.interaction_box(0)
    layer._moving_coordinates = (0, 0, 0)
    layer._is_moving = True
    # need to go through the generator
    _ = list(key_bindings.hold_to_lock_aspect_ratio(layer))
Esempio n. 14
0
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])
Esempio n. 15
0
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)
Esempio n. 16
0
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)
Esempio n. 17
0
def test_blending():
    """Test setting layer blending."""
    np.random.seed(0)
    data = 20 * np.random.random((10, 4, 2))
    layer = Shapes(data)
    assert layer.blending == 'translucent'

    layer.blending = 'additive'
    assert layer.blending == 'additive'

    layer = Shapes(data, blending='additive')
    assert layer.blending == 'additive'

    layer.blending = 'opaque'
    assert layer.blending == 'opaque'
Esempio n. 18
0
def test_opacity():
    """Test setting layer opacity."""
    np.random.seed(0)
    data = 20 * np.random.random((10, 4, 2))
    layer = Shapes(data)
    assert layer.opacity == 0.7

    layer.opacity = 0.5
    assert layer.opacity == 0.5

    layer = Shapes(data, opacity=0.6)
    assert layer.opacity == 0.6

    layer.opacity = 0.3
    assert layer.opacity == 0.3
Esempio n. 19
0
def test_visiblity():
    """Test setting layer visiblity."""
    np.random.seed(0)
    data = 20 * np.random.random((10, 4, 2))
    layer = Shapes(data)
    assert layer.visible == True

    layer.visible = False
    assert layer.visible == False

    layer = Shapes(data, visible=False)
    assert layer.visible == False

    layer.visible = True
    assert layer.visible == True
Esempio n. 20
0
    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)
Esempio n. 21
0
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
Esempio n. 23
0
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'
Esempio n. 24
0
 def _make_shapes_layer(self, shape, shape_type, name, **kwargs):
     layer = Shapes(shape, shape_type=shape_type, name=name, **kwargs)
     self._init_layer(layer)
Esempio n. 25
0
def layer_writer_and_data(request):
    """Fixture that supplies layer io utilities for tests.

    Parameters
    ----------
    request : _pytest.fixtures.SubRequest
        The pytest request object

    Returns
    -------
    tuple
        ``(writer, layer_data, extension, reader, Layer)``

        - writer: a function that can write layerdata to a path
        - layer_data: the layerdata tuple for this layer
        - extension: an appropriate extension for this layer type
        - reader: a function that can read this layer type from a path and
                  returns a ``(data, meta)`` tuple.
        - Layer: the Layer class
    """
    if request.param == 'image':
        data = np.random.rand(20, 20)
        Layer = Image
        layer = Image(data)
        writer = napari_write_image
        extension = '.tif'

        def reader(path):
            return (io.imread(path), {}, 'image')  # metadata

    elif request.param == 'labels':
        data = np.random.randint(0, 16000, (32, 32), 'uint64')
        Layer = Labels
        layer = Labels(data)
        writer = napari_write_labels
        extension = '.tif'

        def reader(path):
            return (io.imread(path), {}, 'labels')  # metadata

    elif request.param == 'points':
        data = np.random.rand(20, 2)
        Layer = Points
        layer = Points(data)
        writer = napari_write_points
        extension = '.csv'
        reader = partial(io.csv_to_layer_data, require_type='points')
    elif request.param == 'points-with-properties':
        data = np.random.rand(20, 2)
        Layer = Points
        layer = Points(data, properties={'values': np.random.rand(20)})
        writer = napari_write_points
        extension = '.csv'
        reader = partial(io.csv_to_layer_data, require_type='points')
    elif request.param == 'shapes':
        np.random.seed(0)
        data = [
            np.random.rand(2, 2),
            np.random.rand(2, 2),
            np.random.rand(6, 2),
            np.random.rand(6, 2),
            np.random.rand(2, 2),
        ]
        shape_type = ['ellipse', 'line', 'path', 'polygon', 'rectangle']
        Layer = Shapes
        layer = Shapes(data, shape_type=shape_type)
        writer = napari_write_shapes
        extension = '.csv'
        reader = partial(io.csv_to_layer_data, require_type='shapes')
    else:
        return None, None, None, None, None

    layer_data = layer.as_layer_data_tuple()
    return writer, layer_data, extension, reader, Layer
Esempio n. 26
0
    data[5, 5] = 1000
    assert data[5, 5] == 1000
    if mode == 'int8' or mode == 'uint8':
        # label value 1000 is outside of the target data type range.
        with pytest.raises(AssertionError):
            _convert_dtype(ll, mode=mode)
        assert ll[-1].data.dtype == np.int16
    else:
        _convert_dtype(ll, mode=mode)
        assert ll[-1].data.dtype == np.dtype(mode)

    assert ll[-1].data[5, 5] == 1000
    assert ll[-1].data.flatten().sum() == 1000


@pytest.mark.parametrize(
    'input, type_',
    [
        (Image(np.random.rand(10, 10)), 'labels'),
        (Labels(np.ones((10, 10), dtype=int)), 'image'),
        (Shapes([np.array([[0, 0], [0, 10], [10, 0], [10, 10]])]), 'labels'),
    ],
)
def test_convert_layer(input, type_):
    ll = LayerList()
    ll.append(input)
    assert ll[0]._type_string != type_
    _convert(ll, type_)
    assert ll[0]._type_string == type_
Esempio n. 27
0
 def time_create_layer(self, n):
     """Time to create a layer."""
     Shapes(self.data, shape_type='polygon')
Esempio n. 28
0
 def setup(self, n):
     np.random.seed(0)
     self.data = [50 * np.random.random((6, 3)) for i in range(n)]
     self.layer = Shapes(self.data, shape_type='polygon')
Esempio n. 29
0
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 = []
    layer._copy_data()
    layer._paste_data()
    assert layer._clipboard == []
    assert len(layer.data) == shape[0] + 4
Esempio n. 30
0
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]