Esempio n. 1
0
    def test_set_item_nd(self):
        map_size = 10
        d = {"iq": np.arange(map_size)}
        props = CrystalMapProperties(d, id=np.arange(map_size))

        # 2D
        prop_2d = np.arange(map_size * 2).reshape((10, 2))
        props["prop_2d"] = prop_2d
        assert np.allclose(props["prop_2d"], prop_2d)

        # 3D
        prop_3d = np.arange(map_size * 4).reshape((10, 2, 2))
        props["prop_3d"] = prop_3d
        assert np.allclose(props["prop_3d"], prop_3d)

        with pytest.raises(IndexError,
                           match="boolean index did not match indexed"):
            props["prop_3d_wrong"] = np.random.random(40).reshape((2, 10, 2))

        # Update 2D array, accounting for in data values
        is_in_data = np.ones(map_size, dtype=bool)
        is_in_data[5] = False
        props.is_in_data = is_in_data
        new_prop_2d = np.arange(map_size * 2).reshape((map_size, 2))
        props["prop_2d"] = new_prop_2d[is_in_data]
        np.allclose(props["prop_2d"], new_prop_2d[is_in_data])
Esempio n. 2
0
    def test_set_item_error(self):
        map_size = 10
        is_in_data = np.ones(map_size, dtype=bool)
        id_to_change = 3
        is_in_data[id_to_change] = False

        d = {"iq": np.arange(map_size)}
        props = CrystalMapProperties(d, id=np.arange(map_size), is_in_data=is_in_data)

        # Set array with an array
        with pytest.raises(ValueError, match="NumPy boolean array indexing assignment"):
            props["iq"] = np.arange(map_size) + 1

        # Set new 2D array
        props.is_in_data[id_to_change] = True
        with pytest.raises(TypeError, match="NumPy boolean array indexing assignment"):
            new_shape = (10 // 2, 10 // 5)
            props["dp"] = np.arange(map_size).reshape(new_shape)
Esempio n. 3
0
    def test_set_item(self):
        map_size = 10
        is_in_data = np.ones(map_size, dtype=bool)
        is_in_data[5] = False
        d = {"iq": np.arange(map_size)}
        props = CrystalMapProperties(d, id=np.arange(map_size), is_in_data=is_in_data)

        # Set array with an array
        n_in_data = map_size - len(np.where(~is_in_data)[0])
        props["iq"] = np.arange(n_in_data) + 1
        expected_array = np.array([1, 2, 3, 4, 5, 5, 6, 7, 8, 9])
        assert np.allclose(props.get("iq"), expected_array)

        # Set array with one value
        props["iq"] = 2
        expected_array2 = np.ones(map_size) * 2
        expected_array2[5] = expected_array[5]
        assert np.allclose(props.get("iq"), expected_array2)
Esempio n. 4
0
    def test_init_properties(self, dictionary, id, is_in_data):
        props = CrystalMapProperties(dictionary=dictionary,
                                     id=id,
                                     is_in_data=is_in_data)

        assert props == dictionary
        assert np.allclose(props.id, id)
        if is_in_data is None:
            is_in_data = np.ones(id.size, dtype=bool)
        assert np.allclose(props.is_in_data, is_in_data)
Esempio n. 5
0
    def test_set_item_error(self):
        map_size = 10
        is_in_data = np.ones(map_size, dtype=bool)
        id_to_change = 3
        is_in_data[id_to_change] = False

        d = {"iq": np.arange(map_size)}
        props = CrystalMapProperties(d,
                                     id=np.arange(map_size),
                                     is_in_data=is_in_data)

        # Set array with an array
        with pytest.raises(ValueError,
                           match="shape mismatch: value array of shape"):
            props["iq"] = np.arange(map_size) + 1

        # Set new 2D array
        props.is_in_data[id_to_change] = True
        with pytest.raises(IndexError,
                           match="boolean index did not match indexed"):
            new_shape = (10 // 2, 10 // 5)
            props["dp"] = np.arange(map_size).reshape(new_shape)
Esempio n. 6
0
    def __init__(
        self,
        rotations,
        phase_id=None,
        x=None,
        y=None,
        z=None,
        phase_list=None,
        prop=None,
        scan_unit=None,
        is_in_data=None,
    ):
        """
        Parameters
        ----------
        rotations : orix.quaternion.rotation.Rotation
            Rotation of each data point. Must be passed with all spatial
            dimensions in the first array axis (flattened). May contain
            multiple rotations per point, included in the second array
            axes. Crystal map data size is set equal to the first array
            axis' size.
        phase_id : numpy.ndarray, optional
            Phase ID of each pixel. IDs equal to -1 are considered not
            indexed. If None is passed (default), all points are
            considered to belong to one phase with ID 0.
        x : numpy.ndarray, optional
            Map x coordinate of each data point. If None is passed,
            the map is assumed to be 1D, and it is set to an array of
            increasing integers from 0 to the length of the `phase_id`
            array.
        y : numpy.ndarray, optional
            Map y coordinate of each data point. If None is passed,
            the map is assumed to be 1D, and it is set to None.
        z : numpy.ndarray, optional
            Map z coordinate of each data point. If None is passed, the
            map is assumed to be 2D or 1D, and it is set to None.
        phase_list : PhaseList, optional
            A list of phases in the data with their with names,
            space groups, point groups, and structures. The order in which
            the phases appear in the list is important, as it is this, and
            not the phases' IDs, that is used to link the phases to the
            input `phase_id` if the IDs aren't exactly the same as in
            `phase_id`. If None (default), a phase list with as many
            phases as there are unique phase IDs in `phase_id` is created.
        prop : dict of numpy.ndarray, optional
            Dictionary of properties of each data point.
        scan_unit : str, optional
            Length unit of the data. If None (default), "px" is used.
        is_in_data : np.ndarray, optional
            Array of booleans signifying whether a point is in the data.

        Examples
        --------
        >>> from diffpy.structure import Atom, Lattice, Structure
        >>> import numpy as np
        >>> from orix.crystal_map import CrystalMap
        >>> from orix.quaternion.rotation import Rotation
        >>> euler1, euler2, euler3, x, y, iq, dp, phase_id = np.loadtxt(
        ...     "/some/file.ang", unpack=True)
        >>> euler_angles = np.column_stack((euler1, euler2, euler3))
        >>> rotations = Rotation.from_euler(euler_angles)
        >>> properties = {"iq": iq, "dp": dp}
        >>> structures = [
        ...     Structure(
        ...         title="austenite",
        ...         atoms=[Atom("fe", [0] * 3)],
        ...         lattice=Lattice(0.360, 0.360, 0.360, 90, 90, 90)
        ...     ),
        ...     Structure(
        ...         title="ferrite",
        ...         atoms=[Atom("fe", [0] * 3)],
        ...         lattice=Lattice(0.287, 0.287, 0.287, 90, 90, 90)
        ...     )
        ... ]
        >>> pl = PhaseList(space_groups=[225, 229], structures=structures)
        >>> cm = CrystalMap(
        ...     rotations=rotations,
        ...     phase_id=phase_id,
        ...     x=x,
        ...     y=y,
        ...     phase_list=pl,
        ...     prop=properties,
        ... )
        """
        # Set rotations
        if not isinstance(rotations, Rotation):
            raise ValueError(
                f"rotations must be of type {Rotation}, not {type(rotations)}."
            )
        self._rotations = rotations

        # Set data size
        data_size = rotations.shape[0]

        # Set phase IDs
        if phase_id is None:  # Assume single phase data
            phase_id = np.zeros(data_size)
        phase_id = phase_id.astype(int)
        self._phase_id = phase_id

        # Set data point IDs
        point_id = np.arange(data_size)
        self._id = point_id

        # Set spatial coordinates
        if x is None and y is None and z is None:
            x = np.arange(data_size)
        self._x = x
        self._y = y
        self._z = z

        # Create phase list
        # Sorted in ascending order
        unique_phase_ids = np.unique(phase_id)
        include_not_indexed = False
        if unique_phase_ids[0] == -1:
            include_not_indexed = True
            unique_phase_ids = unique_phase_ids[1:]
        # Also sorted in ascending order
        if phase_list is None:
            self.phases = PhaseList(ids=unique_phase_ids)
        else:
            phase_list = copy.deepcopy(phase_list)
            phase_ids = phase_list.ids
            n_different = len(phase_ids) - len(unique_phase_ids)
            if n_different > 0:
                # Remove superfluous phases by removing the phases whose
                # ID is not in the ID array, in descending list order
                for i in phase_ids[::-1]:
                    if i not in unique_phase_ids:
                        del phase_list[i]
                        n_different -= 1
                    if n_different == 0:
                        break
            elif n_different < 0:
                # Create new phase list adding the missing phases with
                # default initial values
                phase_list = PhaseList(
                    names=phase_list.names,
                    space_groups=phase_list.space_groups,
                    point_groups=phase_list.point_groups,
                    colors=phase_list.colors,
                    structures=phase_list.structures,
                    ids=unique_phase_ids,
                )
            # Ensure phase list IDs correspond to IDs in phase_id array
            new_ids = list(unique_phase_ids.astype(int))
            phase_list._dict = dict(zip(new_ids, phase_list._dict.values()))
            self.phases = phase_list

        # Set whether measurements are indexed
        is_indexed = np.ones(data_size, dtype=bool)
        is_indexed[np.where(phase_id == -1)] = False

        # Add "not_indexed" to phase list and ensure not indexed points
        # have correct phase ID
        if include_not_indexed:
            self.phases.add_not_indexed()
            self._phase_id[~is_indexed] = -1

        # Set array with True for points in data
        if is_in_data is None:
            is_in_data = np.ones(data_size, dtype=bool)
        self.is_in_data = is_in_data

        # Set scan unit
        if scan_unit is None:
            scan_unit = "px"
        self.scan_unit = scan_unit

        # Set properties
        if prop is None:
            prop = {}
        self._prop = CrystalMapProperties(prop, id=point_id)

        # Set original data shape (needed if data shape changes in
        # __getitem__())
        self._original_shape = self._data_shape_from_coordinates()