Esempio n. 1
0
    def test_ids(self):
        np.random.seed(42)

        # None --> CircuitNodeIds with all ids
        tested = self.test_obj.ids()
        expected = CircuitNodeIds.from_dict({
            "default": [0, 1, 2],
            "default2": [0, 1, 2, 3]
        })
        assert tested == expected
        npt.assert_equal(tested.get_ids().dtype, IDS_DTYPE)

        # CircuitNodeIds --> CircuitNodeIds and check if the population and node ids exist
        ids = CircuitNodeIds.from_arrays(["default", "default2"], [0, 3])
        tested = self.test_obj.ids(ids)
        assert tested == ids

        # default3 population does not exist and is asked explicitly
        with pytest.raises(BluepySnapError):
            ids = CircuitNodeIds.from_arrays(["default", "default3"], [0, 3])
            self.test_obj.ids(ids)

        # (default2, 5) does not exist and is asked explicitly
        with pytest.raises(BluepySnapError):
            ids = CircuitNodeIds.from_arrays(["default", "default2"], [0, 5])
            self.test_obj.ids(ids)

        # single node ID --> CircuitNodeIds return populations with the 0 id
        expected = CircuitNodeIds.from_arrays(["default", "default2"], [0, 0])
        tested = self.test_obj.ids(0)
        assert tested == expected

        # single node ID --> CircuitNodeIds raise if the ID is not in all population
        with pytest.raises(BluepySnapError):
            self.test_obj.ids(3)

        # seq of node ID --> CircuitNodeIds return populations with the array of ids
        expected = CircuitNodeIds.from_arrays(
            ["default", "default", "default2", "default2"], [0, 1, 0, 1])
        tested = self.test_obj.ids([0, 1])
        assert tested == expected
        tested = self.test_obj.ids((0, 1))
        assert tested == expected
        tested = self.test_obj.ids(np.array([0, 1]))
        assert tested == expected

        ids = [CircuitNodeId("default", 0), CircuitNodeId("default", 1)]
        assert self.test_obj.ids(ids) == CircuitNodeIds.from_dict(
            {"default": [0, 1]})

        with pytest.raises(BluepySnapError):
            ids = [CircuitNodeId("default", 0), ("default", 1)]
            self.test_obj.ids(ids)

        # seq node ID --> CircuitNodeIds raise if on ID is not in all populations
        with pytest.raises(BluepySnapError):
            self.test_obj.ids([0, 1, 2, 3])

        # node sets
        assert self.test_obj.ids('Layer2') == CircuitNodeIds.from_arrays(
            ["default", 'default2'], [0, 3])
        assert self.test_obj.ids('Layer23') == CircuitNodeIds.from_arrays(
            ["default", 'default2'], [0, 3])
        assert self.test_obj.ids(
            'Population_default_L6_Y_Node2') == CircuitNodeIds.from_arrays(
                ["default"], [2])
        assert self.test_obj.ids('combined_combined_Node0_L6_Y__Node12_L6_Y__'
                                 ) == CircuitNodeIds.from_arrays([
                                     "default", "default", "default",
                                     "default2"
                                 ], [0, 1, 2, 3])

        # Mapping --> CircuitNodeIds query on the populations empty dict return all
        assert self.test_obj.ids({}) == self.test_obj.ids()

        # Mapping --> CircuitNodeIds query on the populations
        tested = self.test_obj.ids({'layer': 2})
        expected = CircuitNodeIds.from_arrays(["default", "default2"], [0, 3])
        assert tested == expected

        # Mapping --> CircuitNodeIds query on the populations no raise if not in one of the pop
        tested = self.test_obj.ids({'other1': ['A', 'D']})
        expected = CircuitNodeIds.from_arrays(["default2", "default2"], [0, 3])
        assert tested == expected

        # Mapping --> CircuitNodeIds query on the populations no raise if not in one of the pop
        tested = self.test_obj.ids({'other1': ['A', 'D'], 'layer': 2})
        expected = CircuitNodeIds.from_arrays(["default2"], [3])
        assert tested == expected

        # Mapping --> CircuitNodeIds query on the populations no raise if not in one of the pop
        tested = self.test_obj.ids(
            {'$or': [{
                'other1': ['A', 'D']
            }, {
                'layer': 2
            }]})
        expected = CircuitNodeIds.from_arrays(
            ["default", "default2", "default2"], [0, 0, 3])
        assert tested == expected

        # Mapping --> CircuitNodeIds query on the populations no raise if not in one of the pop
        tested = self.test_obj.ids(
            {'$and': [{
                'other1': ['A', 'D']
            }, {
                'layer': 2
            }]})
        expected = CircuitNodeIds.from_arrays(["default2"], [3])
        assert tested == expected

        # Mapping --> CircuitNodeIds query on the population node ids with mapping.
        # single pop
        tested = self.test_obj.ids({"population": "default"})
        expected = self.test_obj.ids().filter_population("default")
        assert tested == expected
        # multiple pop
        tested = self.test_obj.ids({"population": ["default", "default2"]})
        expected = self.test_obj.ids()
        assert tested == expected
        # not existing pop (should not raise)
        tested = self.test_obj.ids({"population": "default4"})
        expected = CircuitNodeIds.from_arrays([], [])
        assert tested == expected

        # single pop and node ids
        tested = self.test_obj.ids({
            "population": ["default"],
            "node_id": [1, 2]
        })
        expected = CircuitNodeIds.from_arrays(["default", "default"], [1, 2])
        assert tested == expected
        # single pop and node ids with not present node id (should not raise)
        tested = self.test_obj.ids({
            "population": ["default"],
            "node_id": [1, 5]
        })
        expected = CircuitNodeIds.from_arrays(["default"], [1])
        assert tested == expected
        # not existing node ids (should not raise)
        tested = self.test_obj.ids({
            "population": ["default"],
            "node_id": [5, 6, 7]
        })
        expected = CircuitNodeIds.from_arrays([], [])
        assert tested == expected

        # multiple pop and node ids
        tested = self.test_obj.ids({
            "population": ["default", "default2"],
            "node_id": [1, 0]
        })
        expected = CircuitNodeIds.from_arrays(
            ["default", "default", "default2", "default2"], [1, 0, 1, 0])
        assert tested == expected
        # multiple pop and node ids with not present node id (should not raise)
        tested = self.test_obj.ids({
            "population": ["default", "default2"],
            "node_id": [1, 0, 3]
        })
        expected = CircuitNodeIds.from_arrays(
            ["default", "default", "default2", "default2", "default2"],
            [1, 0, 1, 0, 3])
        assert tested == expected

        # Check operations on global ids
        ids = self.test_obj.ids()
        assert ids.filter_population("default").append(
            ids.filter_population("default2")) == ids

        expected = CircuitNodeIds.from_arrays(["default2", "default2"], [0, 1])
        assert ids.filter_population("default2").limit(2) == expected

        tested = self.test_obj.ids(sample=2)
        expected = CircuitNodeIds.from_arrays(["default2", "default2"], [3, 0],
                                              sort_index=False)
        assert tested == expected

        tested = self.test_obj.ids(limit=4)
        expected = CircuitNodeIds.from_dict({
            "default": [0, 1, 2],
            "default2": [0]
        })
        assert tested == expected
Esempio n. 2
0
    def test_get(self):
        tested = self.test_obj.get()
        pdt.assert_series_equal(
            tested, _create_series([2, 0, 1, 2, 0], [0.1, 0.2, 0.3, 0.7, 1.3]))
        npt.assert_equal(tested.dtype, IDS_DTYPE)

        pdt.assert_series_equal(self.test_obj.get([]), _create_series([], []))
        pdt.assert_series_equal(self.test_obj.get(np.array([])),
                                _create_series([], []))
        pdt.assert_series_equal(self.test_obj.get(()), _create_series([], []))
        pdt.assert_series_equal(self.test_obj.get(2),
                                _create_series([2, 2], [0.1, 0.7]))

        pdt.assert_series_equal(self.test_obj.get(CircuitNodeId("default", 2)),
                                _create_series([2, 2], [0.1, 0.7]))
        # not in population
        pdt.assert_series_equal(
            self.test_obj.get(CircuitNodeId("default2", 2)),
            _create_series([], []))

        pdt.assert_series_equal(self.test_obj.get(0, t_start=1.0),
                                _create_series([0], [1.3]))
        pdt.assert_series_equal(self.test_obj.get(0, t_stop=1.0),
                                _create_series([0], [0.2]))
        pdt.assert_series_equal(self.test_obj.get(0, t_start=1.0, t_stop=12),
                                _create_series([0], [1.3]))
        pdt.assert_series_equal(self.test_obj.get(0, t_start=0.1, t_stop=12),
                                _create_series([0, 0], [0.2, 1.3]))

        pdt.assert_series_equal(
            self.test_obj.get([2, 0]),
            _create_series([2, 0, 2, 0], [0.1, 0.2, 0.7, 1.3]))

        pdt.assert_series_equal(
            self.test_obj.get([0, 2]),
            _create_series([2, 0, 2, 0], [0.1, 0.2, 0.7, 1.3]))

        pdt.assert_series_equal(
            self.test_obj.get(np.asarray([0, 2])),
            _create_series([2, 0, 2, 0], [0.1, 0.2, 0.7, 1.3]),
        )

        pdt.assert_series_equal(self.test_obj.get([2], t_stop=0.5),
                                _create_series([2], [0.1]))

        pdt.assert_series_equal(self.test_obj.get([2], t_start=0.5),
                                _create_series([2], [0.7]))

        pdt.assert_series_equal(
            self.test_obj.get([2], t_start=0.5, t_stop=0.8),
            _create_series([2], [0.7]))

        pdt.assert_series_equal(
            self.test_obj.get([2, 1], t_start=0.5, t_stop=0.8),
            _create_series([2], [0.7]))

        pdt.assert_series_equal(
            self.test_obj.get([2, 1], t_start=0.2, t_stop=0.8),
            _create_series([1, 2], [0.3, 0.7]))

        pdt.assert_series_equal(
            self.test_obj.get(group={Cell.MTYPE: "L6_Y"},
                              t_start=0.2,
                              t_stop=0.8),
            _create_series([1, 2], [0.3, 0.7]),
        )

        pdt.assert_series_equal(self.test_obj.get(group={Cell.MTYPE: "L2_X"}),
                                _create_series([0, 0], [0.2, 1.3]))

        pdt.assert_series_equal(self.test_obj.get(group="Layer23"),
                                _create_series([0, 0], [0.2, 1.3]))

        # no 0.1, 0.7 from  ("default2", 2)
        ids = CircuitNodeIds.from_arrays(["default", "default", "default2"],
                                         [0, 1, 2])
        npt.assert_array_equal(self.test_obj.get(ids),
                               _create_series([0, 1, 0], [0.2, 0.3, 1.3]))

        with pytest.raises(BluepySnapError):
            self.test_obj.get([-1], t_start=0.2)

        with pytest.raises(BluepySnapError):
            self.test_obj.get([0, 2], t_start=-1)

        with pytest.raises(BluepySnapError):
            self.test_obj.get([0, 2], t_start=12)

        with pytest.raises(BluepySnapError):
            self.test_obj.get(4)
Esempio n. 3
0
    def test_ids(self):
        _call = self.test_obj.ids
        npt.assert_equal(_call(), [0, 1, 2])
        npt.assert_equal(_call(group={}), [0, 1, 2])
        npt.assert_equal(_call(group=[]), [])
        npt.assert_equal(_call(limit=1), [0])
        # limit too big compared to the number of ids
        npt.assert_equal(_call(limit=15), [0, 1, 2])
        npt.assert_equal(len(_call(sample=2)), 2)
        # if sample > population.size --> sample = population.size
        npt.assert_equal(len(_call(sample=25)), 3)
        npt.assert_equal(_call(group=[], sample=2), [])
        npt.assert_equal(_call(group={Cell.MTYPE: "unknown"}, sample=2), [])
        npt.assert_equal(_call(0), [0])
        npt.assert_equal(_call([0, 1]), [0, 1])
        npt.assert_equal(_call([1, 0, 1]),
                         [1, 0, 1])  # order and duplicates preserved
        npt.assert_equal(_call(np.array([1, 0, 1])), np.array([1, 0, 1]))

        # NodeCircuitId
        npt.assert_equal(_call(CircuitNodeId("default", 0)), [0])
        # List of NodeCircuitId
        npt.assert_equal(
            _call([CircuitNodeId("default", 0),
                   CircuitNodeId("default", 1)]), [0, 1])
        # tuple of NodeCircuitId
        npt.assert_equal(
            _call((CircuitNodeId("default", 0), CircuitNodeId("default", 1))),
            [0, 1])
        # NodeCircuitId with wrong population
        npt.assert_equal(_call(CircuitNodeId("default2", 0)), [])
        npt.assert_equal(
            _call([CircuitNodeId("default2", 0),
                   CircuitNodeId("default2", 1)]), [])
        # NodeCircuitId list with one wrong population and one ok
        npt.assert_equal(
            _call([CircuitNodeId("default2", 0),
                   CircuitNodeId("default", 1)]), [1])

        # NodeCircuitIds
        ids = CircuitNodeIds.from_arrays(["default", "default"], [0, 1])
        npt.assert_equal(_call(ids), [0, 1])
        # returns only the ids for the default population
        ids = CircuitNodeIds.from_arrays(["default", "default", "default2"],
                                         [0, 1, 0])
        npt.assert_equal(_call(ids), [0, 1])
        # returns only the ids for the default population so should be []
        ids = CircuitNodeIds.from_arrays(["default2", "default2", "default2"],
                                         [0, 1, 2])
        npt.assert_equal(_call(ids), [])

        npt.assert_equal(_call({Cell.MTYPE: 'L6_Y'}), [1, 2])
        npt.assert_equal(_call({Cell.X: (100, 203)}), [0, 1])
        npt.assert_equal(
            _call({
                Cell.MTYPE: 'L6_Y',
                Cell.MORPHOLOGY: "morph-B"
            }), [1])

        npt.assert_equal(_call({"node_id": 1}), [1])
        npt.assert_equal(_call({"node_id": [1]}), [1])
        npt.assert_equal(_call({"node_id": [1, 2]}), [1, 2])
        npt.assert_equal(_call({"node_id": [1, 2, 42]}), [1, 2])
        npt.assert_equal(
            _call({
                "node_id": [1],
                "population": ["default"],
                Cell.MORPHOLOGY: "morph-B"
            }), [1])

        # same query with a $and operator
        npt.assert_equal(
            _call(
                {"$and": [{
                    Cell.MTYPE: 'L6_Y'
                }, {
                    Cell.MORPHOLOGY: "morph-B"
                }]}), [1])
        npt.assert_equal(_call({Cell.MORPHOLOGY: ['morph-A', 'morph-B']}),
                         [0, 1])
        npt.assert_equal(_call({"$and": [{}, {}]}), [0, 1, 2])
        npt.assert_equal(_call({"$and": [{}, {
            Cell.MORPHOLOGY: 'morph-B'
        }]}), [1])
        # same query with a $or operator
        npt.assert_equal(
            _call({
                "$or": [{
                    Cell.MORPHOLOGY: 'morph-A'
                }, {
                    Cell.MORPHOLOGY: 'morph-B'
                }]
            }), [0, 1])
        npt.assert_equal(
            _call(
                {"$or": [{
                    Cell.MTYPE: 'L6_Y'
                }, {
                    Cell.MORPHOLOGY: "morph-B"
                }]}), [1, 2])
        npt.assert_equal(_call({"$or": [{}, {}]}), [0, 1, 2])
        npt.assert_equal(_call({"$or": [{}, {
            Cell.MORPHOLOGY: 'morph-B'
        }]}), [0, 1, 2])
        # non destructive operation for queries
        query = {
            "$and": [{
                "$or": [{
                    Cell.MTYPE: 'L6_Y'
                }, {
                    Cell.MORPHOLOGY: "morph-B"
                }]
            }, {
                "node_id": [1]
            }]
        }
        npt.assert_equal(_call(query), [1])
        npt.assert_equal(_call(query), [1])

        npt.assert_equal(_call('Layer2'), [0])
        npt.assert_equal(_call('Layer23'), [0])
        npt.assert_equal(_call('Empty_nodes'), [])
        npt.assert_equal(_call('Node2012'),
                         [0, 1, 2])  # reordered + duplicates are removed
        npt.assert_equal(_call('Node12_L6_Y'), [1, 2])
        npt.assert_equal(_call('Node2_L6_Y'), [2])

        npt.assert_equal(_call('Node0_L6_Y'),
                         [])  # return empty if disjoint samples
        npt.assert_equal(_call('Empty_L6_Y'),
                         [])  # return empty if empty node_id = []
        npt.assert_equal(_call('Population_default'),
                         [0, 1, 2])  # return all ids
        npt.assert_equal(_call('Population_default2'),
                         [])  # return empty if diff population
        npt.assert_equal(_call('Population_default_L6_Y'),
                         [1, 2])  # population + other query ok
        # population + other query + node_id ok
        npt.assert_equal(_call('Population_default_L6_Y_Node2'), [2])
        npt.assert_equal(_call('combined_Node0_L6_Y__Node12_L6_Y'),
                         [1, 2])  # 'or' function
        npt.assert_equal(_call('combined_combined_Node0_L6_Y__Node12_L6_Y__'),
                         [0, 1, 2])  # imbricated '$or' functions

        npt.assert_equal(_call({
            "$node_set": 'Node12_L6_Y',
            "node_id": 1
        }), [1])
        npt.assert_equal(
            _call({
                "$node_set": 'Node12_L6_Y',
                "node_id": [1, 2, 3]
            }), [1, 2])
        npt.assert_equal(
            _call({
                "$node_set": 'Node12_L6_Y',
                "population": "default"
            }), [1, 2])
        npt.assert_equal(
            _call({
                "$node_set": 'Node12_L6_Y',
                "population": "default",
                "node_id": 1
            }), [1])
        npt.assert_equal(
            _call({
                "$node_set": 'Node12_L6_Y',
                Cell.MORPHOLOGY: "morph-B"
            }), [1])
        npt.assert_equal(
            _call({
                "$and": [{
                    "$node_set": 'Node12_L6_Y',
                    "population": "default"
                }, {
                    Cell.MORPHOLOGY: "morph-B"
                }]
            }), [1])
        npt.assert_equal(
            _call({
                "$or": [{
                    "$node_set": 'Node12_L6_Y',
                    "population": "default"
                }, {
                    Cell.MORPHOLOGY: "morph-B"
                }]
            }), [1, 2])

        with pytest.raises(BluepySnapError):
            _call('no-such-node-set')
        with pytest.raises(BluepySnapError):
            _call(-1)  # node ID out of range (lower boundary)
        with pytest.raises(BluepySnapError):
            _call([-1, 1])  # one of node IDs out of range (lower boundary)
        with pytest.raises(BluepySnapError):
            _call([
                1, -1
            ])  # one of node IDs out of range, reversed order (lower boundary)
        with pytest.raises(BluepySnapError):
            _call(999)  # node ID out of range (upper boundary)
        with pytest.raises(BluepySnapError):
            _call([1, 999])  # one of node IDs out of range
        with pytest.raises(BluepySnapError):
            _call({'no-such-node-property': 42})
        with pytest.raises(BluepySnapError):
            _call({"$node_set": [1, 2]})
        with pytest.raises(BluepySnapError):
            _call({"$node_set": 'no-such-node-set'})
        with pytest.raises(BluepySnapError):
            _call([
                CircuitNodeId("default", 1),
                CircuitNodeId("default2", 1), ("default2", 1)
            ])
Esempio n. 4
0
    def test_orientations(self):
        _call = self.test_obj.orientations
        expected = [
            [0.738219, 0., 0.674560],
            [0., 1., 0.],
            [-0.674560, 0., 0.738219],
        ]
        npt.assert_almost_equal(_call(0), expected, decimal=6)
        npt.assert_almost_equal(_call(CircuitNodeId("default", 0)),
                                expected,
                                decimal=6)
        pdt.assert_series_equal(
            _call([2, 0, 1]),
            pd.Series([
                np.array([
                    [0.462986, 0., 0.886365],
                    [0., 1., 0.],
                    [-0.886365, 0., 0.462986],
                ]),
                np.array([
                    [0.738219, 0., 0.674560],
                    [0., 1., 0.],
                    [-0.674560, 0., 0.738219],
                ]),
                np.array([[-0.86768965, -0.44169042, 0.22808825],
                          [0.48942842, -0.8393853, 0.23641518],
                          [0.0870316, 0.31676788, 0.94450178]])
            ],
                      index=[2, 0, 1],
                      name='orientation'))

        # NodeCircuitIds
        pdt.assert_series_equal(
            _call(
                CircuitNodeIds.from_arrays(["default", "default", "default"],
                                           [2, 0, 1],
                                           sort_index=False)), _call([2, 0,
                                                                      1]))

        # NodePopulation without rotation_angle[x|z]
        _call_no_xz = create_node_population(
            str(TEST_DATA_DIR / 'nodes_no_xz_rotation.h5'),
            "default").orientations
        # 0 and 2 node_ids have x|z rotation angles equal to zero
        npt.assert_almost_equal(_call_no_xz(0), _call(0))
        npt.assert_almost_equal(_call_no_xz(2), _call(2))
        npt.assert_almost_equal(_call_no_xz(1),
                                [[0.97364046, -0., 0.22808825], [0., 1., -0.],
                                 [-0.22808825, 0., 0.97364046]],
                                decimal=6)

        # NodePopulation without rotation_angle
        _call_no_rot = create_node_population(
            str(TEST_DATA_DIR / 'nodes_no_rotation.h5'),
            "default").orientations

        pdt.assert_series_equal(
            _call_no_rot([2, 0, 1]),
            pd.Series([np.eye(3), np.eye(3), np.eye(3)],
                      index=[2, 0, 1],
                      name='orientation'))

        # NodePopulation with quaternions
        _call_quat = create_node_population(
            str(TEST_DATA_DIR / 'nodes_quaternions.h5'),
            "default").orientations

        npt.assert_almost_equal(_call_quat(0), [
            [1, 0., 0.],
            [0., 0, -1.],
            [0., 1., 0],
        ],
                                decimal=6)

        series = _call_quat([2, 0, 1])
        for i in range(len(series)):
            series.iloc[i] = np.around(series.iloc[i],
                                       decimals=1).astype(np.float64)

        pdt.assert_series_equal(
            series,
            pd.Series([
                np.array([
                    [0., -1., 0.],
                    [1., 0., 0.],
                    [0., 0., 1.],
                ]),
                np.array([
                    [1., 0., 0.],
                    [0., 0., -1.],
                    [0., 1., 0.],
                ]),
                np.array([
                    [0., 0., 1.],
                    [0., 1., 0.],
                    [-1., 0., 0.],
                ])
            ],
                      index=[2, 0, 1],
                      name='orientation'))

        _call_missing_quat = create_node_population(
            str(TEST_DATA_DIR / 'nodes_quaternions_w_missing.h5'),
            "default").orientations

        with pytest.raises(BluepySnapError):
            _call_missing_quat(0)
Esempio n. 5
0
    def test_get(self):
        _call = self.test_obj.get
        assert _call().shape == (3, 12)
        assert _call(0, Cell.MTYPE) == "L2_X"
        assert _call(CircuitNodeId("default", 0), Cell.MTYPE) == "L2_X"
        assert _call(np.int32(0), Cell.MTYPE) == "L2_X"
        pdt.assert_frame_equal(
            _call([1, 2],
                  properties=[Cell.X, Cell.MTYPE, Cell.HOLDING_CURRENT]),
            pd.DataFrame(
                [
                    [201.0, "L6_Y", 0.2],
                    [301.0, "L6_Y", 0.3],
                ],
                columns=[Cell.X, Cell.MTYPE, Cell.HOLDING_CURRENT],
                index=[1, 2],
            ),
        )

        # NodeCircuitId same as [1, 2] for the default
        pdt.assert_frame_equal(
            _call(
                CircuitNodeIds.from_dict({"default": [1, 2]}),
                properties=[Cell.X, Cell.MTYPE, Cell.HOLDING_CURRENT],
            ),
            pd.DataFrame(
                [
                    [201.0, "L6_Y", 0.2],
                    [301.0, "L6_Y", 0.3],
                ],
                columns=[Cell.X, Cell.MTYPE, Cell.HOLDING_CURRENT],
                index=[1, 2],
            ),
        )

        # NodeCircuitId only consider the default population
        pdt.assert_frame_equal(
            _call(
                CircuitNodeIds.from_arrays(["default", "default", "default2"],
                                           [1, 2, 0]),
                properties=[Cell.X, Cell.MTYPE, Cell.HOLDING_CURRENT],
            ),
            pd.DataFrame(
                [
                    [201.0, "L6_Y", 0.2],
                    [301.0, "L6_Y", 0.3],
                ],
                columns=[Cell.X, Cell.MTYPE, Cell.HOLDING_CURRENT],
                index=[1, 2],
            ),
        )

        pdt.assert_frame_equal(
            _call("Node12_L6_Y", properties=[Cell.X, Cell.MTYPE, Cell.LAYER]),
            pd.DataFrame(
                [
                    [201.0, "L6_Y", 6],
                    [301.0, "L6_Y", 6],
                ],
                columns=[Cell.X, Cell.MTYPE, Cell.LAYER],
                index=[1, 2],
            ),
        )

        assert _call("Node0_L6_Y", properties=[Cell.X, Cell.MTYPE,
                                               Cell.LAYER]).empty
        assert _call(1, properties=[Cell.MTYPE]).tolist() == ["L6_Y"]
        assert _call([1], properties=Cell.MTYPE).tolist() == ["L6_Y"]
        assert _call([1, 2],
                     properties=Cell.MTYPE).tolist() == ["L6_Y", "L6_Y"]
        with pytest.raises(BluepySnapError):
            _call(0, properties="no-such-property")
        with pytest.raises(BluepySnapError):
            _call(999)  # invalid node id
        with pytest.raises(BluepySnapError):
            _call([0, 999])  # one of node ids is invalid