Example #1
0
    def add_xray_lines_markers(self, xray_lines):
        """
        Add marker on a spec.plot() with the name of the selected X-ray
        lines

        Parameters
        ----------
        xray_lines: list of string
            A valid list of X-ray lines
        """

        line_energy = []
        intensity = []
        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy.append(self._get_line_energy(xray_line))
            relative_factor = elements_db[element][
                'Atomic_properties']['Xray_lines'][line]['weight']
            a_eng = self._get_line_energy(element + '_' + line[0] + 'a')
            intensity.append(self.isig[a_eng].data * relative_factor)
        for i in range(len(line_energy)):
            line = markers.vertical_line_segment(
                x=line_energy[i], y1=None, y2=intensity[i] * 0.8)
            self.add_marker(line, render_figure=False)
            string = (r'$\mathrm{%s}_{\mathrm{%s}}$' %
                      utils_eds._get_element_and_line(xray_lines[i]))
            text = markers.text(
                x=line_energy[i], y=intensity[i] * 1.1, text=string,
                rotation=90)
            self.add_marker(text, render_figure=False)
            self._xray_markers[xray_lines[i]] = [line, text]
            line.events.closed.connect(self._xray_marker_closed)
            text.events.closed.connect(self._xray_marker_closed)
        self._render_figure(plot=['signal_plot'])
Example #2
0
    def _add_xray_lines_markers(self, xray_lines):
        """
        Add marker on a spec.plot() with the name of the selected X-ray
        lines

        Parameters
        ----------
        xray_lines: list of string
            A valid list of X-ray lines
        """

        line_energy = []
        intensity = []
        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy.append(self._get_line_energy(xray_line))
            relative_factor = elements_db[element][
                'Atomic_properties']['Xray_lines'][line]['weight']
            a_eng = self._get_line_energy(element + '_' + line[0] + 'a')
            intensity.append(self.isig[a_eng].data * relative_factor)
        for i in range(len(line_energy)):
            line = markers.vertical_line_segment(
                x=line_energy[i], y1=None, y2=intensity[i] * 0.8)
            self.add_marker(line)
            text = markers.text(
                x=line_energy[i], y=intensity[i] * 1.1, text=xray_lines[i],
                rotation=90)
            self.add_marker(text)
            self._xray_markers[xray_lines[i]] = (line, text)
Example #3
0
 def _make_position_adjuster(self, component, fix_it, show_label):
     # Override to ensure formatting of labels of xray lines
     super(EDSModel, self)._make_position_adjuster(component, fix_it,
                                                   show_label)
     if show_label and component in (self.xray_lines + self.family_lines):
         label = self._position_widgets[component._position][1]
         label.string = (r"$\mathrm{%s}_{\mathrm{%s}}$" %
                         _get_element_and_line(component.name))
Example #4
0
 def _make_position_adjuster(self, component, fix_it, show_label):
     # Override to ensure formatting of labels of xray lines
     super(EDSModel, self)._make_position_adjuster(
         component, fix_it, show_label)
     if show_label and component in (self.xray_lines + self.family_lines):
         label = self._position_widgets[component._position][1]
         label.string = (r"$\mathrm{%s}_{\mathrm{%s}}$" %
                         _get_element_and_line(component.name))
Example #5
0
    def add_xray_lines_markers(self, xray_lines, render_figure=True):
        """
        Add marker on a spec.plot() with the name of the selected X-ray
        lines

        Parameters
        ----------
        xray_lines: list of string
            A valid list of X-ray lines
        """

        line_energy = []
        intensity = []
        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy.append(self._get_line_energy(xray_line))
            relative_factor = elements_db[element]['Atomic_properties'][
                'Xray_lines'][line]['weight']
            a_eng = self._get_line_energy(f'{element}_{line[0]}a')
            idx = self.axes_manager.signal_axes[0].value2index(a_eng)
            intensity.append(self.data[..., idx] * relative_factor)
        for i in range(len(line_energy)):
            line = markers.vertical_line_segment(x=line_energy[i],
                                                 y1=None,
                                                 y2=intensity[i] * 0.8)
            self.add_marker(line, render_figure=False)
            string = (r'$\mathrm{%s}_{\mathrm{%s}}$' %
                      utils_eds._get_element_and_line(xray_lines[i]))
            text = markers.text(x=line_energy[i],
                                y=intensity[i] * 1.1,
                                text=string,
                                rotation=90)
            self.add_marker(text, render_figure=False)
            self._xray_markers[xray_lines[i]] = [line, text]
            line.events.closed.connect(self._xray_marker_closed)
            text.events.closed.connect(self._xray_marker_closed)
        if render_figure:
            self._render_figure(plot=['signal_plot'])
Example #6
0
    def estimate_integration_windows(self,
                                     windows_width=2.,
                                     xray_lines=None):
        """
        Estimate a window of integration for each X-ray line.

        Parameters
        ----------
        windows_width: float
            The width of the integration windows is the 'windows_width' times
            the calculated FWHM of the line.
        xray_lines: None or list of string
            If None, use 'metadata.Sample.elements.xray_lines'. Else,
            provide an iterable containing a list of valid X-ray lines
            symbols.

        Return
        ------
        integration_windows: 2D array of float
            The positions of the windows in energy. Each row corresponds to a
            X-ray line. Each row contains the left and right value of the
            window.

        Examples
        --------
        >>> s = utils.example_signals.EDS_TEM_Spectrum()
        >>> s.add_lines()
        >>> iw = s.estimate_integration_windows()
        >>> s.plot(integration_windows=iw)
        >>> s.get_lines_intensity(integration_windows=iw, plot_result=True)
        Fe_Ka at 6.4039 keV : Intensity = 3710.00
        Pt_La at 9.4421 keV : Intensity = 15872.00

        See also
        --------
        plot, get_lines_intensity
        """
        if xray_lines is None:
            xray_lines = self.metadata.Sample.xray_lines
        integration_windows = []
        for Xray_line in xray_lines:
            line_energy, line_FWHM = self._get_line_energy(Xray_line,
                                                           FWHM_MnKa='auto')
            element, line = utils_eds._get_element_and_line(Xray_line)
            det = windows_width * line_FWHM / 2.
            integration_windows.append([line_energy - det, line_energy + det])
        return integration_windows
Example #7
0
    def estimate_integration_windows(self,
                                     windows_width=2.,
                                     xray_lines=None):
        """
        Estimate a window of integration for each X-ray line.

        Parameters
        ----------
        windows_width: float
            The width of the integration windows is the 'windows_width' times
            the calculated FWHM of the line.
        xray_lines: None or list of string
            If None, use 'metadata.Sample.elements.xray_lines'. Else,
            provide an iterable containing a list of valid X-ray lines
            symbols.

        Return
        ------
        integration_windows: 2D array of float
            The positions of the windows in energy. Each row corresponds to a
            X-ray line. Each row contains the left and right value of the
            window.

        Examples
        --------
        >>> s = hs.datasets.example_signals.EDS_TEM_Spectrum()
        >>> s.add_lines()
        >>> iw = s.estimate_integration_windows()
        >>> s.plot(integration_windows=iw)
        >>> s.get_lines_intensity(integration_windows=iw, plot_result=True)
        Fe_Ka at 6.4039 keV : Intensity = 3710.00
        Pt_La at 9.4421 keV : Intensity = 15872.00

        See also
        --------
        plot, get_lines_intensity
        """
        xray_lines = self._get_xray_lines(xray_lines)
        integration_windows = []
        for Xray_line in xray_lines:
            line_energy, line_FWHM = self._get_line_energy(Xray_line,
                                                           FWHM_MnKa='auto')
            element, line = utils_eds._get_element_and_line(Xray_line)
            det = windows_width * line_FWHM / 2.
            integration_windows.append([line_energy - det, line_energy + det])
        return integration_windows
Example #8
0
 def fix_twin(component):
     component.A.bmin = 0.0
     component.A.bmax = None
     element, line = utils_eds._get_element_and_line(component.name)
     for li in elements_db[element]["Atomic_properties"]["Xray_lines"]:
         if line[0] in li and line != li:
             xray_sub = element + "_" + li
             if xray_sub in self:
                 component_sub = self[xray_sub]
                 component_sub.A.bmin = 1e-10
                 component_sub.A.bmax = None
                 weight_line = component_sub.A.value / component.A.value
                 component_sub.A.twin_function = _get_weight(element, li, weight_line)
                 component_sub.A.twin_inverse_function = _get_iweight(element, li, weight_line)
                 component_sub.A.twin = component.A
             else:
                 warnings.warn("The X-ray line expected to be in the " "model was not found")
Example #9
0
 def fix_twin(component):
     component.A.bmin = 0.0
     component.A.bmax = None
     element, line = utils_eds._get_element_and_line(component.name)
     for li in elements_db[element]['Atomic_properties']['Xray_lines']:
         if line[0] in li and line != li:
             xray_sub = element + '_' + li
             if xray_sub in self:
                 component_sub = self[xray_sub]
                 component_sub.A.bmin = 1e-10
                 component_sub.A.bmax = None
                 weight_line = component_sub.A.value / component.A.value
                 component_sub.A.twin_function_expr = _get_weight(
                     element, li, weight_line)
                 component_sub.A.twin = component.A
             else:
                 warnings.warn("The X-ray line expected to be in the "
                               "model was not found")
Example #10
0
    def add_family_lines(self, xray_lines='from_elements'):
        """Create the Xray-lines instances and configure them appropiately

        If a X-ray line is given, all the the lines of the familiy is added.
        For instance if Zn Ka is given, Zn Kb is added too. The main lines
        (alpha) is added to self.xray_lines

        Parameters
        -----------
        xray_lines: {None, 'from_elements', list of string}
            If None, if `metadata` contains `xray_lines` list of lines use
            those. If 'from_elements', add all lines from the elements contains
            in `metadata`. Alternatively, provide an iterable containing
            a list of valid X-ray lines symbols. (eg. ('Al_Ka','Zn_Ka')).
        """

        only_one = False
        only_lines = ("Ka", "La", "Ma")

        if xray_lines is None or xray_lines == 'from_elements':
            if 'Sample.xray_lines' in self.signal.metadata \
                    and xray_lines != 'from_elements':
                xray_lines = self.signal.metadata.Sample.xray_lines
            elif 'Sample.elements' in self.signal.metadata:
                xray_lines = self.signal._get_lines_from_elements(
                    self.signal.metadata.Sample.elements,
                    only_one=only_one,
                    only_lines=only_lines)
            else:
                raise ValueError(
                    "No elements defined, set them with `add_elements`")

        components_names = [xr.name for xr in self.xray_lines]
        xray_lines = filter(lambda x: x not in components_names, xray_lines)
        xray_lines, xray_not_here = self.signal.\
            _get_xray_lines_in_spectral_range(xray_lines)
        for xray in xray_not_here:
            warnings.warn("%s is not in the data energy range." % (xray))

        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy, line_FWHM = self.signal._get_line_energy(
                xray_line,
                FWHM_MnKa='auto')
            component = create_component.Gaussian()
            component.centre.value = line_energy
            component.fwhm = line_FWHM
            component.centre.free = False
            component.sigma.free = False
            component.name = xray_line
            self.append(component)
            self.xray_lines.append(component)
            self[xray_line].A.map[
                'values'] = self.signal.isig[line_energy].data * \
                line_FWHM / self.signal.axes_manager[-1].scale
            self[xray_line].A.map['is_set'] = (
                np.ones(self.signal.isig[line_energy].data.shape) == 1)
            component.A.ext_force_positive = True
            for li in elements_db[element]['Atomic_properties']['Xray_lines']:
                if line[0] in li and line != li:
                    xray_sub = element + '_' + li
                    if self.signal.\
                            _get_xray_lines_in_spectral_range(
                                [xray_sub])[0] != []:
                        line_energy, line_FWHM = self.signal.\
                            _get_line_energy(
                                xray_sub, FWHM_MnKa='auto')
                        component_sub = create_component.Gaussian()
                        component_sub.centre.value = line_energy
                        component_sub.fwhm = line_FWHM
                        component_sub.centre.free = False
                        component_sub.sigma.free = False
                        component_sub.name = xray_sub
                        component_sub.A.twin_function = _get_weight(
                            element, li)
                        component_sub.A.twin_inverse_function = _get_iweight(
                            element, li)
                        component_sub.A.twin = component.A
                        self.append(component_sub)
                        self.family_lines.append(component_sub)
            self.fetch_stored_values()
Example #11
0
    def quantification(self,
                       intensities,
                       method,
                       factors,
                       composition_units='atomic',
                       absorption_correction=False,
                       take_off_angle='auto',
                       thickness='auto',
                       convergence_criterion=0.5,
                       navigation_mask=1.0,
                       closing=True,
                       plot_result=False,
                       probe_area='auto',
                       max_iterations=30,
                       show_progressbar=None,
                       **kwargs):
        """
        Absorption corrected quantification using Cliff-Lorimer, the zeta-factor
        method, or ionization cross sections. The function iterates through
        quantification function until two successive interations don't change
        the final composition by a defined percentage critera (0.5% by default).

        Parameters
        ----------
        intensities: list of signal
            the intensitiy for each X-ray lines.
        method: {'CL', 'zeta', 'cross_section'}
            Set the quantification method: Cliff-Lorimer, zeta-factor, or
            ionization cross sections.
        factors: list of float
            The list of kfactors, zeta-factors or cross sections in same order
            as intensities. Note that intensities provided by Hyperspy are
            sorted by the alphabetical order of the X-ray lines.
            eg. factors =[0.982, 1.32, 1.60] for ['Al_Ka', 'Cr_Ka', 'Ni_Ka'].
        composition_units: {'atomic', 'weight'}
            The quantification returns the composition in 'atomic' percent by
            default, but can also return weight percent if specified.
        absorption_correction: bool
            Specify whether or not an absorption correction should be applied.
            'False' by default so absorption will not be applied unless
            specfied.
        take_off_angle : {'auto'}
            The angle between the sample surface and the vector along which
            X-rays travel to reach the centre of the detector.
        thickness: {'auto'}
            thickness in nm (can be a single value or
            have the same navigation dimension as the signal).
            NB: Must be specified for 'CL' method. For 'zeta' or 'cross_section'
            methods, first quantification step provides a mass_thickness
            internally during quantification.
        convergence_criterion: The convergence criterium defined as the percentage
            difference between 2 successive iterations. 0.5% by default.
        navigation_mask : None or float or signal
            The navigation locations marked as True are not used in the
            quantification. If float is given the vacuum_mask method is used to
            generate a mask with the float value as threhsold.
            Else provides a signal with the navigation shape. Only for the
            'Cliff-Lorimer' method.
        closing: bool
            If true, applied a morphologic closing to the mask obtained by
            vacuum_mask.
        plot_result : bool
            If True, plot the calculated composition. If the current
            object is a single spectrum it prints the result instead.
        probe_area = {'auto'}
            This allows the user to specify the probe_area for interaction with
            the sample needed specifically for the cross_section method of
            quantification. When left as 'auto' the pixel area is used,
            calculated from the navigation axes information.
        max_iterations : int
            An upper limit to the number of calculations for absorption correction.
        kwargs
            The extra keyword arguments are passed to plot.

        Returns
        -------
        A list of quantified elemental maps (signal) giving the composition of
        the sample in weight or atomic percent with absorption correciton taken
        into account based on the sample thickness estimate provided.

        If the method is 'zeta' this function also returns the mass thickness
        profile for the data.

        If the method is 'cross_section' this function also returns the atom
        counts for each element.

        Examples
        --------
        >>> s = hs.datasets.example_signals.EDS_TEM_Spectrum()
        >>> s.add_lines()
        >>> kfactors = [1.450226, 5.075602] #For Fe Ka and Pt La
        >>> bw = s.estimate_background_windows(line_width=[5.0, 2.0])
        >>> s.plot(background_windows=bw)
        >>> intensities = s.get_lines_intensity(background_windows=bw)
        >>> res = s.quantification(intensities, kfactors, plot_result=True,
        >>>                        composition_units='atomic')
        Fe (Fe_Ka): Composition = 15.41 atomic percent
        Pt (Pt_La): Composition = 84.59 atomic percent

        See also
        --------
        vacuum_mask
        """
        if isinstance(navigation_mask, float):
            if self.axes_manager.navigation_dimension > 0:
                navigation_mask = self.vacuum_mask(navigation_mask, closing)
            else:
                navigation_mask = None

        xray_lines = [
            intensity.metadata.Sample.xray_lines[0]
            for intensity in intensities
        ]
        it = 0
        if absorption_correction:
            if show_progressbar is None:  # pragma: no cover
                show_progressbar = preferences.General.show_progressbar
            if show_progressbar:
                pbar = progressbar(total=None,
                                   desc='Absorption correction calculation')

        composition = utils.stack(intensities,
                                  lazy=False,
                                  show_progressbar=False)

        if take_off_angle == 'auto':
            toa = self.get_take_off_angle()
        else:
            toa = take_off_angle

        #determining illumination area for cross sections quantification.
        if method == 'cross_section':
            if probe_area == 'auto':
                parameters = self.metadata.Acquisition_instrument.TEM
                if probe_area in parameters:
                    probe_area = parameters.TEM.probe_area
                else:
                    probe_area = self.get_probe_area(
                        navigation_axes=self.axes_manager.navigation_axes)

        int_stack = utils.stack(intensities,
                                lazy=False,
                                show_progressbar=False)
        comp_old = np.zeros_like(int_stack.data)

        abs_corr_factor = None  # initial

        if method == 'CL':
            quantification_method = utils_eds.quantification_cliff_lorimer
            kwargs = {
                "intensities": int_stack.data,
                "kfactors": factors,
                "absorption_correction": abs_corr_factor,
                "mask": navigation_mask
            }

        elif method == 'zeta':
            quantification_method = utils_eds.quantification_zeta_factor
            kwargs = {
                "intensities": int_stack.data,
                "zfactors": factors,
                "dose": self._get_dose(method),
                "absorption_correction": abs_corr_factor
            }

        elif method == 'cross_section':
            quantification_method = utils_eds.quantification_cross_section
            kwargs = {
                "intensities": int_stack.data,
                "cross_sections": factors,
                "dose": self._get_dose(method, **kwargs),
                "absorption_correction": abs_corr_factor
            }

        else:
            raise ValueError('Please specify method for quantification, '
                             'as "CL", "zeta" or "cross_section".')

        while True:
            results = quantification_method(**kwargs)

            if method == 'CL':
                composition.data = results * 100.
                if absorption_correction:
                    if thickness is not None:
                        mass_thickness = intensities[0].deepcopy()
                        mass_thickness.data = self.CL_get_mass_thickness(
                            composition.split(), thickness)
                        mass_thickness.metadata.General.title = 'Mass thickness'
                    else:
                        raise ValueError(
                            'Thickness is required for absorption correction '
                            'with k-factor method. Results will contain no '
                            'correction for absorption.')

            elif method == 'zeta':
                composition.data = results[0] * 100
                mass_thickness = intensities[0].deepcopy()
                mass_thickness.data = results[1]

            else:
                composition.data = results[0] * 100.
                number_of_atoms = composition._deepcopy_with_new_data(
                    results[1])

            if method == 'cross_section':
                if absorption_correction:
                    abs_corr_factor = utils_eds.get_abs_corr_cross_section(
                        composition.split(), number_of_atoms.split(), toa,
                        probe_area)
                    kwargs["absorption_correction"] = abs_corr_factor
            else:
                if absorption_correction:
                    abs_corr_factor = utils_eds.get_abs_corr_zeta(
                        composition.split(), mass_thickness, toa)
                    kwargs["absorption_correction"] = abs_corr_factor

            res_max = np.max(composition.data - comp_old)
            comp_old = composition.data

            if absorption_correction and show_progressbar:
                pbar.update(1)
            it += 1
            if not absorption_correction or abs(
                    res_max) < convergence_criterion:
                break
            elif it >= max_iterations:
                raise Exception('Absorption correction failed as solution '
                                f'did not converge after {max_iterations} '
                                'iterations')

        if method == 'cross_section':
            number_of_atoms = composition._deepcopy_with_new_data(results[1])
            number_of_atoms = number_of_atoms.split()
            composition = composition.split()
        else:
            composition = composition.split()

        #convert ouput units to selection as required.
        if composition_units == 'atomic':
            if method != 'cross_section':
                composition = utils.material.weight_to_atomic(composition)
        else:
            if method == 'cross_section':
                composition = utils.material.atomic_to_weight(composition)

        #Label each of the elemental maps in the image stacks for composition.
        for i, xray_line in enumerate(xray_lines):
            element, line = utils_eds._get_element_and_line(xray_line)
            composition[i].metadata.General.title = composition_units + \
                ' percent of ' + element
            composition[i].metadata.set_item("Sample.elements", ([element]))
            composition[i].metadata.set_item("Sample.xray_lines",
                                             ([xray_line]))
            if plot_result and composition[i].axes_manager.navigation_size == 1:
                c = np.float(composition[i].data)
                print(
                    f"{element} ({xray_line}): Composition = {c:.2f} percent")
        #For the cross section method this is repeated for the number of atom maps
        if method == 'cross_section':
            for i, xray_line in enumerate(xray_lines):
                element, line = utils_eds._get_element_and_line(xray_line)
                number_of_atoms[i].metadata.General.title = \
                    'atom counts of ' + element
                number_of_atoms[i].metadata.set_item("Sample.elements",
                                                     ([element]))
                number_of_atoms[i].metadata.set_item("Sample.xray_lines",
                                                     ([xray_line]))
        if plot_result and composition[i].axes_manager.navigation_size != 1:
            utils.plot.plot_signals(composition, **kwargs)

        if absorption_correction:
            _logger.info(f'Conversion found after {it} interations.')

        if method == 'zeta':
            mass_thickness.metadata.General.title = 'Mass thickness'
            self.metadata.set_item("Sample.mass_thickness", mass_thickness)
            return composition, mass_thickness
        elif method == 'cross_section':
            return composition, number_of_atoms
        elif method == 'CL':
            if absorption_correction:
                mass_thickness.metadata.General.title = 'Mass thickness'
                return composition, mass_thickness
            else:
                return composition
        else:
            raise ValueError('Please specify method for quantification, as '
                             '"CL", "zeta" or "cross_section"')
Example #12
0
    def get_lines_intensity(self,
                            Xray_lines=None,
                            plot_result=False,
                            integration_window_factor=2.,
                            only_one=True,
                            only_lines=("Ka", "La", "Ma"),):
        """Return the intensity map of selected Xray lines.
        
        The intensity maps are computed by integrating the spectrum over the 
        different X-ray lines. The integration window width
        is calculated from the energy resolution of the detector
        defined as defined in 
        `self.mapped_parameters.SEM.EDS.energy_resolution_MnKa` or 
        `self.mapped_parameters.SEM.EDS.energy_resolution_MnKa`.
        
        
        Parameters
        ----------
        
        Xray_lines: {None, "best", list of string}
            If None,
            if `mapped.parameters.Sample.elements.Xray_lines` contains a 
            list of lines use those.
            If `mapped.parameters.Sample.elements.Xray_lines` is undefined
            or empty but `mapped.parameters.Sample.elements` is defined, 
            use the same syntax as `add_line` to select a subset of lines
            for the operation.
            Alternatively, provide an iterable containing 
            a list of valid X-ray lines symbols.
        plot_result : bool
            If True, plot the calculated line intensities. If the current 
            object is a single spectrum it prints the result instead.
        integration_window_factor: Float
            The integration window is centered at the center of the X-ray
            line and its width is defined by this factor (2 by default) 
            times the calculated FWHM of the line.
        only_one : bool
            If False, use all the lines of each element in the data spectral
            range. If True use only the line at the highest energy
            above an overvoltage of 2 (< beam energy / 2).
        only_lines : {None, list of strings}
            If not None, use only the given lines.
            
        Returns
        -------
        intensities : list
            A list containing the intensities as Signal subclasses.
            
        Examples
        --------
        
        >>> specImg.plot_intensity_map(["C_Ka", "Ta_Ma"])
        
        See also
        --------
        
        set_elements, add_elements.
        
        """

        if Xray_lines is None:
            if 'Sample.Xray_lines' in self.mapped_parameters:
                Xray_lines = self.mapped_parameters.Sample.Xray_lines
            elif 'Sample.elements' in self.mapped_parameters:
                Xray_lines = self._get_lines_from_elements(
                        self.mapped_parameters.Sample.elements,
                        only_one=only_one,
                        only_lines=only_lines)
            else:
                raise ValueError(
                    "Not X-ray line, set them with `add_elements`")
                            
        if self.mapped_parameters.signal_type == 'EDS_SEM':
            FWHM_MnKa = self.mapped_parameters.SEM.EDS.energy_resolution_MnKa
        elif self.mapped_parameters.signal_type == 'EDS_TEM':
            FWHM_MnKa = self.mapped_parameters.TEM.EDS.energy_resolution_MnKa
        else:
            raise NotImplementedError(
                "This method only works for EDS_TEM or EDS_SEM signals. "
                "You can use `set_signal_type(\"EDS_TEM\")` or"
                "`set_signal_type(\"EDS_SEM\")` to convert to one of these"
                "signal types.")                 
        intensities = []
        #test 1D Spectrum (0D problem)
            #signal_to_index = self.axes_manager.navigation_dimension - 2                  
        for Xray_line in Xray_lines:
            element, line = utils_eds._get_element_and_line(Xray_line)           
            line_energy = elements_db[element]['Xray_energy'][line]
            line_FWHM = FWHM_eds(FWHM_MnKa,line_energy)
            det = integration_window_factor * line_FWHM / 2.
            img = self[...,line_energy - det:line_energy + det
                    ].integrate_simpson(-1)
            img.mapped_parameters.title = (
                'Intensity of %s at %.2f %s from %s' % 
                (Xray_line,
                 line_energy,
                 self.axes_manager.signal_axes[0].units,
                 self.mapped_parameters.title)) 
            if img.axes_manager.navigation_dimension >= 2:
                img = img.as_image([0,1])
            elif img.axes_manager.navigation_dimension == 1:
                img.axes_manager.set_signal_dimension(1)
            if plot_result:
                if img.axes_manager.signal_dimension != 0:
                    img.plot()
                else:
                    print("%s at %s %s : Intensity = %.2f" 
                    % (Xray_line,
                       line_energy,
                       self.axes_manager.signal_axes[0].units,
                       img.data))
            intensities.append(img)
        return intensities
Example #13
0
    def quantification(self,
                       intensities,
                       kfactors,
                       composition_units='weight',
                       navigation_mask=1.0,
                       closing=True,
                       plot_result=False,
                       **kwargs):
        """
        Quantification of intensities to return elemental composition

        Method: Cliff-Lorimer

        Parameters
        ----------
        intensities: list of signal
            the intensitiy for each X-ray lines.
        kfactors: list of float
            The list of kfactor in same order as intensities. Note that
            intensities provided by hyperspy are sorted by the aplhabetical
            order of the X-ray lines. eg. kfactors =[0.982, 1.32, 1.60] for
            ['Al_Ka','Cr_Ka', 'Ni_Ka'].
        composition_units: 'weight' or 'atomic'
            Quantification returns weight percent. By choosing 'atomic', the
            return composition is in atomic percent.
        navigation_mask : None or float or signal
            The navigation locations marked as True are not used in the
            quantification. If int is given the vacuum_mask method is used to
            generate a mask with the int value as threhsold.
            Else provides a signal with the navigation shape.
        closing: bool
            If true, applied a morphologic closing to the mask obtained by
            vacuum_mask.
        plot_result : bool
            If True, plot the calculated composition. If the current
            object is a single spectrum it prints the result instead.
        kwargs
            The extra keyword arguments are passed to plot.

        Return
        ------
        A list of quantified elemental maps (signal) giving the composition of
        the sample in weight or atomic percent.

        Examples
        --------
        >>> s = utils.example_signals.EDS_TEM_Spectrum()
        >>> s.add_lines()
        >>> kfactors = [1.450226, 5.075602] #For Fe Ka and Pt La
        >>> bw = s.estimate_background_windows(line_width=[5.0, 2.0])
        >>> s.plot(background_windows=bw)
        >>> intensities = s.get_lines_intensity(background_windows=bw)
        >>> res = s.quantification(intensities, kfactors, plot_result=True,
        >>>                        composition_units='atomic')
        Fe (Fe_Ka): Composition = 15.41 atomic percent
        Pt (Pt_La): Composition = 84.59 atomic percent

        See also
        --------
        vacuum_mask
        """
        if isinstance(navigation_mask, float):
            navigation_mask = self.vacuum_mask(navigation_mask, closing).data
        elif navigation_mask is not None:
            navigation_mask = navigation_mask.data
        xray_lines = self.metadata.Sample.xray_lines
        composition = utils.stack(intensities)
        composition.data = utils_eds.quantification_cliff_lorimer(
            composition.data, kfactors=kfactors,
            mask=navigation_mask) * 100.
        composition = composition.split()
        if composition_units == 'atomic':
            composition = utils.material.weight_to_atomic(composition)
        for i, xray_line in enumerate(xray_lines):
            element, line = utils_eds._get_element_and_line(xray_line)
            composition[i].metadata.General.title = composition_units + \
                ' percent of ' + element
            composition[i].metadata.set_item("Sample.elements", ([element]))
            composition[i].metadata.set_item(
                "Sample.xray_lines", ([xray_line]))
            if plot_result and \
                    composition[i].axes_manager.signal_dimension == 0:
                print("%s (%s): Composition = %.2f %s percent"
                      % (element, xray_line, composition[i].data,
                         composition_units))
        if plot_result and composition[i].axes_manager.signal_dimension != 0:
            utils.plot.plot_signals(composition, **kwargs)
        return composition
Example #14
0
    def get_lines_intensity(self,
                            xray_lines=None,
                            integration_windows=2.,
                            background_windows=None,
                            plot_result=False,
                            only_one=True,
                            only_lines=("a",),
                            **kwargs):
        """Return the intensity map of selected Xray lines.

        The intensities, the number of X-ray counts, are computed by
        suming the spectrum over the
        different X-ray lines. The sum window width
        is calculated from the energy resolution of the detector
        as defined in 'energy_resolution_MnKa' of the metadata.
        Backgrounds average in provided windows can be subtracted from the
        intensities.

        Parameters
        ----------
        xray_lines: {None, "best", list of string}
            If None,
            if `metadata.Sample.elements.xray_lines` contains a
            list of lines use those.
            If `metadata.Sample.elements.xray_lines` is undefined
            or empty but `metadata.Sample.elements` is defined,
            use the same syntax as `add_line` to select a subset of lines
            for the operation.
            Alternatively, provide an iterable containing
            a list of valid X-ray lines symbols.
        integration_windows: Float or array
            If float, the width of the integration windows is the
            'integration_windows_width' times the calculated FWHM of the line.
            Else provide an array for which each row corresponds to a X-ray
            line. Each row contains the left and right value of the window.
        background_windows: None or 2D array of float
            If None, no background subtraction. Else, the backgrounds average
            in the windows are subtracted from the return intensities.
            'background_windows' provides the position of the windows in
            energy. Each line corresponds to a X-ray line. In a line, the two
            first values correspond to the limits of the left window and the
            two last values correspond to the limits of the right window.
        plot_result : bool
            If True, plot the calculated line intensities. If the current
            object is a single spectrum it prints the result instead.
        only_one : bool
            If False, use all the lines of each element in the data spectral
            range. If True use only the line at the highest energy
            above an overvoltage of 2 (< beam energy / 2).
        only_lines : {None, list of strings}
            If not None, use only the given lines.
        kwargs
            The extra keyword arguments for plotting. See
            `utils.plot.plot_signals`

        Returns
        -------
        intensities : list
            A list containing the intensities as Signal subclasses.

        Examples
        --------
        >>> s = hs.datasets.example_signals.EDS_SEM_Spectrum()
        >>> s.get_lines_intensity(['Mn_Ka'], plot_result=True)
        Mn_La at 0.63316 keV : Intensity = 96700.00

        >>> s = hs.datasets.example_signals.EDS_SEM_Spectrum()
        >>> s.plot(['Mn_Ka'], integration_windows=2.1)
        >>> s.get_lines_intensity(['Mn_Ka'],
        >>>                       integration_windows=2.1, plot_result=True)
        Mn_Ka at 5.8987 keV : Intensity = 53597.00

        >>> s = hs.datasets.example_signals.EDS_SEM_Spectrum()
        >>> s.set_elements(['Mn'])
        >>> s.set_lines(['Mn_Ka'])
        >>> bw = s.estimate_background_windows()
        >>> s.plot(background_windows=bw)
        >>> s.get_lines_intensity(background_windows=bw, plot_result=True)
        Mn_Ka at 5.8987 keV : Intensity = 46716.00

        See also
        --------
        set_elements, add_elements, estimate_background_windows,
        plot

        """

        only_lines = utils_eds._parse_only_lines(only_lines)
        xray_lines = self._get_xray_lines(xray_lines, only_one=only_one,
                                          only_lines=only_lines)
        xray_lines, xray_not_here = self._get_xray_lines_in_spectral_range(
            xray_lines)
        for xray in xray_not_here:
            warnings.warn("%s is not in the data energy range." % xray +
                          "You can remove it with" +
                          "s.metadata.Sample.xray_lines.remove('%s')"
                          % xray)
        if hasattr(integration_windows, '__iter__') is False:
            integration_windows = self.estimate_integration_windows(
                windows_width=integration_windows, xray_lines=xray_lines)
        intensities = []
        ax = self.axes_manager.signal_axes[0]
        # test 1D Spectrum (0D problem)
        # signal_to_index = self.axes_manager.navigation_dimension - 2
        for i, (Xray_line, window) in enumerate(
                zip(xray_lines, integration_windows)):
            line_energy, line_FWHM = self._get_line_energy(Xray_line,
                                                           FWHM_MnKa='auto')
            element, line = utils_eds._get_element_and_line(Xray_line)
            img = self.isig[window[0]:window[1]].integrate1D(-1)
            if background_windows is not None:
                bw = background_windows[i]
                # TODO: test to prevent slicing bug. To be reomved when fixed
                indexes = [float(ax.value2index(de))
                           for de in list(bw) + window]
                if indexes[0] == indexes[1]:
                    bck1 = self.isig[bw[0]]
                else:
                    bck1 = self.isig[bw[0]:bw[1]].integrate1D(-1)
                if indexes[2] == indexes[3]:
                    bck2 = self.isig[bw[2]]
                else:
                    bck2 = self.isig[bw[2]:bw[3]].integrate1D(-1)
                corr_factor = (indexes[5] - indexes[4]) / (
                    (indexes[1] - indexes[0]) + (indexes[3] - indexes[2]))
                img -= (bck1 + bck2) * corr_factor
            img.metadata.General.title = (
                'X-ray line intensity of %s: %s at %.2f %s' %
                (self.metadata.General.title,
                 Xray_line,
                 line_energy,
                 self.axes_manager.signal_axes[0].units,
                 ))
            if img.axes_manager.navigation_dimension >= 2:
                img = img.as_image([0, 1])
            elif img.axes_manager.navigation_dimension == 1:
                img.axes_manager.set_signal_dimension(1)
            if plot_result and img.axes_manager.signal_dimension == 0:
                print("%s at %s %s : Intensity = %.2f"
                      % (Xray_line,
                         line_energy,
                         ax.units,
                         img.data))
            img.metadata.set_item("Sample.elements", ([element]))
            img.metadata.set_item("Sample.xray_lines", ([Xray_line]))
            intensities.append(img)
        if plot_result and img.axes_manager.signal_dimension != 0:
            utils.plot.plot_signals(intensities, **kwargs)
        return intensities
Example #15
0
def test_get_element_and_line():
    assert _get_element_and_line('Mn_Ka') == ('Mn', 'Ka')

    with pytest.raises(ValueError):
        _get_element_and_line('MnKa') == -1
Example #16
0
    def _get_line_energy(self, Xray_line, FWHM_MnKa=None):
        """
        Get the line energy and the energy resolution of a Xray line.

        The return values are in the same units than the signal axis

        Parameters
        ----------

        Xray_line : strings
            Valid element X-ray lines e.g. Fe_Kb.

        FWHM_MnKa: {None, float, 'auto'}
            The energy resolution of the detector in eV
            if 'auto', used the one in
            'self.metadata.Acquisition_instrument.SEM.Detector.EDS.energy_resolution_MnKa'

        Returns
        ------

        float: the line energy, if FWHM_MnKa is None
        (float,float): the line energy and the energy resolution, if FWHM_MnKa is not None
        """

        units_name = self.axes_manager.signal_axes[0].units
        element, line = utils_eds._get_element_and_line(Xray_line)

        if FWHM_MnKa == 'auto':
            if self.metadata.Signal.signal_type == 'EDS_SEM':
                FWHM_MnKa = self.metadata.Acquisition_instrument.SEM.Detector.EDS.energy_resolution_MnKa
            elif self.metadata.Signal.signal_type == 'EDS_TEM':
                FWHM_MnKa = self.metadata.Acquisition_instrument.TEM.Detector.EDS.energy_resolution_MnKa
            else:
                raise NotImplementedError(
                    "This method only works for EDS_TEM or EDS_SEM signals. "
                    "You can use `set_signal_type(\"EDS_TEM\")` or"
                    "`set_signal_type(\"EDS_SEM\")` to convert to one of these"
                    "signal types.")

        if units_name == 'eV':
            line_energy = elements_db[element]['Atomic_properties']['Xray_lines'][
                line]['energy (keV)'] * 1000
            if FWHM_MnKa is not None:
                line_FWHM = utils_eds.get_FWHM_at_Energy(FWHM_MnKa,
                                                         line_energy / 1000) * 1000
        elif units_name == 'keV':
            line_energy = elements_db[element]['Atomic_properties']['Xray_lines'][
                line]['energy (keV)']
            if FWHM_MnKa is not None:
                line_FWHM = utils_eds.get_FWHM_at_Energy(FWHM_MnKa,
                                                         line_energy)
        else:
            raise ValueError(
                "%s is not a valid units for the energy axis. "
                "Only `eV` and `keV` are supported. "
                "If `s` is the variable containing this EDS spectrum:\n "
                ">>> s.axes_manager.signal_axes[0].units = \'keV\' \n"
                % (units_name))
        if FWHM_MnKa is None:
            return line_energy
        else:
            return line_energy, line_FWHM
Example #17
0
    def _get_line_energy(self, Xray_line, FWHM_MnKa=None):
        """
        Get the line energy and the energy resolution of a Xray line.

        The return values are in the same units than the signal axis

        Parameters
        ----------

        Xray_line : strings
            Valid element X-ray lines e.g. Fe_Kb.

        FWHM_MnKa: {None, float, 'auto'}
            The energy resolution of the detector in eV
            if 'auto', used the one in
            'self.metadata.Acquisition_instrument.SEM.Detector.EDS.energy_resolution_MnKa'

        Returns
        ------

        float: the line energy, if FWHM_MnKa is None
        (float,float): the line energy and the energy resolution, if FWHM_MnKa is not None
        """

        units_name = self.axes_manager.signal_axes[0].units
        element, line = utils_eds._get_element_and_line(Xray_line)

        if FWHM_MnKa == 'auto':
            if self.metadata.Signal.signal_type == 'EDS_SEM':
                FWHM_MnKa = self.metadata.Acquisition_instrument.SEM.Detector.EDS.energy_resolution_MnKa
            elif self.metadata.Signal.signal_type == 'EDS_TEM':
                FWHM_MnKa = self.metadata.Acquisition_instrument.TEM.Detector.EDS.energy_resolution_MnKa
            else:
                raise NotImplementedError(
                    "This method only works for EDS_TEM or EDS_SEM signals. "
                    "You can use `set_signal_type(\"EDS_TEM\")` or"
                    "`set_signal_type(\"EDS_SEM\")` to convert to one of these"
                    "signal types.")

        if units_name == 'eV':
            line_energy = elements_db[element]['Atomic_properties'][
                'Xray_lines'][line]['energy (keV)'] * 1000
            if FWHM_MnKa is not None:
                line_FWHM = utils_eds.get_FWHM_at_Energy(
                    FWHM_MnKa, line_energy / 1000) * 1000
        elif units_name == 'keV':
            line_energy = elements_db[element]['Atomic_properties'][
                'Xray_lines'][line]['energy (keV)']
            if FWHM_MnKa is not None:
                line_FWHM = utils_eds.get_FWHM_at_Energy(
                    FWHM_MnKa, line_energy)
        else:
            raise ValueError(
                "%s is not a valid units for the energy axis. "
                "Only `eV` and `keV` are supported. "
                "If `s` is the variable containing this EDS spectrum:\n "
                ">>> s.axes_manager.signal_axes[0].units = \'keV\' \n" %
                (units_name))
        if FWHM_MnKa is None:
            return line_energy
        else:
            return line_energy, line_FWHM
Example #18
0
    def add_family_lines(self, xray_lines='from_elements'):
        """Create the Xray-lines instances and configure them appropiately

        If a X-ray line is given, all the the lines of the familiy is added.
        For instance if Zn Ka is given, Zn Kb is added too. The main lines
        (alpha) is added to self.xray_lines

        Parameters
        -----------
        xray_lines: {None, 'from_elements', list of string}
            If None, if `metadata` contains `xray_lines` list of lines use
            those. If 'from_elements', add all lines from the elements contains
            in `metadata`. Alternatively, provide an iterable containing
            a list of valid X-ray lines symbols. (eg. ('Al_Ka','Zn_Ka')).
        """

        only_one = False
        only_lines = ("Ka", "La", "Ma")

        if xray_lines is None or xray_lines == 'from_elements':
            if 'Sample.xray_lines' in self.signal.metadata \
                    and xray_lines != 'from_elements':
                xray_lines = self.signal.metadata.Sample.xray_lines
            elif 'Sample.elements' in self.signal.metadata:
                xray_lines = self.signal._get_lines_from_elements(
                    self.signal.metadata.Sample.elements,
                    only_one=only_one,
                    only_lines=only_lines)
            else:
                raise ValueError(
                    "No elements defined, set them with `add_elements`")

        components_names = [xr.name for xr in self.xray_lines]
        xray_lines = filter(lambda x: x not in components_names, xray_lines)
        xray_lines, xray_not_here = self.signal.\
            _get_xray_lines_in_spectral_range(xray_lines)
        for xray in xray_not_here:
            warnings.warn("%s is not in the data energy range." % (xray))

        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy, line_FWHM = self.signal._get_line_energy(
                xray_line, FWHM_MnKa='auto')
            component = create_component.Gaussian()
            component.centre.value = line_energy
            component.fwhm = line_FWHM
            component.centre.free = False
            component.sigma.free = False
            component.name = xray_line
            self.append(component)
            self.xray_lines.append(component)
            self[xray_line].A.map[
                'values'] = self.signal.isig[line_energy].data * \
                line_FWHM / self.signal.axes_manager[-1].scale
            self[xray_line].A.map['is_set'] = (np.ones(
                self.signal.isig[line_energy].data.shape) == 1)
            component.A.ext_force_positive = True
            for li in elements_db[element]['Atomic_properties']['Xray_lines']:
                if line[0] in li and line != li:
                    xray_sub = element + '_' + li
                    if self.signal.\
                            _get_xray_lines_in_spectral_range(
                                [xray_sub])[0] != []:
                        line_energy, line_FWHM = self.signal.\
                            _get_line_energy(
                                xray_sub, FWHM_MnKa='auto')
                        component_sub = create_component.Gaussian()
                        component_sub.centre.value = line_energy
                        component_sub.fwhm = line_FWHM
                        component_sub.centre.free = False
                        component_sub.sigma.free = False
                        component_sub.name = xray_sub
                        component_sub.A.twin_function = _get_weight(
                            element, li)
                        component_sub.A.twin_inverse_function = _get_iweight(
                            element, li)
                        component_sub.A.twin = component.A
                        self.append(component_sub)
            self.fetch_stored_values()
Example #19
0
    def get_lines_intensity(self,
                            xray_lines=None,
                            plot_result=False,
                            **kwargs):
        """
        Return the fitted intensity of the X-ray lines.

        Return the area under the gaussian corresping to the X-ray lines

        Parameters
        ----------
        xray_lines: list of str or None or 'from_metadata'
            If None, all main X-ray lines (alpha)
            If 'from_metadata', take the Xray_lines stored in the `metadata`
            of the spectrum. Alternatively, provide an iterable containing
            a list of valid X-ray lines symbols.
        plot_result : bool
            If True, plot the calculated line intensities. If the current
            object is a single spectrum it prints the result instead.
        kwargs
            The extra keyword arguments for plotting. See
            `utils.plot.plot_signals`

        Returns
        -------
        intensities : list
            A list containing the intensities as Signal subclasses.

        Examples
        --------
        >>> m.multifit()
        >>> m.get_lines_intensity(["C_Ka", "Ta_Ma"])
        """
        from hyperspy import utils
        intensities = []
        if xray_lines is None:
            xray_lines = [component.name for component in self.xray_lines]
        else:
            if xray_lines == 'from_metadata':
                xray_lines = self.signal.metadata.Sample.xray_lines
            xray_lines = filter(lambda x: x in [a.name for a in
                                                self], xray_lines)
        if not xray_lines:
            raise ValueError("These X-ray lines are not part of the model.")
        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy = self.signal._get_line_energy(xray_line)
            data_res = self[xray_line].A.map['values']
            if self.axes_manager.navigation_dimension == 0:
                data_res = data_res[0]
            img = self.signal.isig[0:1].integrate1D(-1)
            img.data = data_res
            img.metadata.General.title = (
                'Intensity of %s at %.2f %s from %s' %
                (xray_line,
                 line_energy,
                 self.signal.axes_manager.signal_axes[0].units,
                 self.signal.metadata.General.title))
            if img.axes_manager.navigation_dimension >= 2:
                img = img.as_signal2D([0, 1])
            elif img.axes_manager.navigation_dimension == 1:
                img.axes_manager.set_signal_dimension(1)
            if plot_result and img.axes_manager.signal_dimension == 0:
                print("%s at %s %s : Intensity = %.2f"
                      % (xray_line,
                         line_energy,
                         self.signal.axes_manager.signal_axes[0].units,
                         img.data))
            img.metadata.set_item("Sample.elements", ([element]))
            img.metadata.set_item("Sample.xray_lines", ([xray_line]))
            intensities.append(img)
        if plot_result and img.axes_manager.signal_dimension != 0:
            utils.plot.plot_signals(intensities, **kwargs)
        return intensities
Example #20
0
    def get_lines_intensity(
            self,
            Xray_lines=None,
            plot_result=False,
            integration_window_factor=2.,
            only_one=True,
            only_lines=("Ka", "La", "Ma"),
    ):
        """Return the intensity map of selected Xray lines.
        
        The intensity maps are computed by integrating the spectrum over the 
        different X-ray lines. The integration window width
        is calculated from the energy resolution of the detector
        defined as defined in 
        `self.mapped_parameters.SEM.EDS.energy_resolution_MnKa` or 
        `self.mapped_parameters.SEM.EDS.energy_resolution_MnKa`.
        
        
        Parameters
        ----------
        
        Xray_lines: {None, "best", list of string}
            If None,
            if `mapped.parameters.Sample.elements.Xray_lines` contains a 
            list of lines use those.
            If `mapped.parameters.Sample.elements.Xray_lines` is undefined
            or empty but `mapped.parameters.Sample.elements` is defined, 
            use the same syntax as `add_line` to select a subset of lines
            for the operation.
            Alternatively, provide an iterable containing 
            a list of valid X-ray lines symbols.
        plot_result : bool
            If True, plot the calculated line intensities. If the current 
            object is a single spectrum it prints the result instead.
        integration_window_factor: Float
            The integration window is centered at the center of the X-ray
            line and its width is defined by this factor (2 by default) 
            times the calculated FWHM of the line.
        only_one : bool
            If False, use all the lines of each element in the data spectral
            range. If True use only the line at the highest energy
            above an overvoltage of 2 (< beam energy / 2).
        only_lines : {None, list of strings}
            If not None, use only the given lines.
            
        Returns
        -------
        intensities : list
            A list containing the intensities as Signal subclasses.
            
        Examples
        --------
        
        >>> specImg.plot_intensity_map(["C_Ka", "Ta_Ma"])
        
        See also
        --------
        
        set_elements, add_elements.
        
        """

        if Xray_lines is None:
            if 'Sample.Xray_lines' in self.mapped_parameters:
                Xray_lines = self.mapped_parameters.Sample.Xray_lines
            elif 'Sample.elements' in self.mapped_parameters:
                Xray_lines = self._get_lines_from_elements(
                    self.mapped_parameters.Sample.elements,
                    only_one=only_one,
                    only_lines=only_lines)
            else:
                raise ValueError(
                    "Not X-ray line, set them with `add_elements`")

        if self.mapped_parameters.signal_type == 'EDS_SEM':
            FWHM_MnKa = self.mapped_parameters.SEM.EDS.energy_resolution_MnKa
        elif self.mapped_parameters.signal_type == 'EDS_TEM':
            FWHM_MnKa = self.mapped_parameters.TEM.EDS.energy_resolution_MnKa
        else:
            raise NotImplementedError(
                "This method only works for EDS_TEM or EDS_SEM signals. "
                "You can use `set_signal_type(\"EDS_TEM\")` or"
                "`set_signal_type(\"EDS_SEM\")` to convert to one of these"
                "signal types.")
        intensities = []
        #test 1D Spectrum (0D problem)
        #signal_to_index = self.axes_manager.navigation_dimension - 2
        for Xray_line in Xray_lines:
            element, line = utils_eds._get_element_and_line(Xray_line)
            line_energy = elements_db[element]['Xray_energy'][line]
            line_FWHM = FWHM_eds(FWHM_MnKa, line_energy)
            det = integration_window_factor * line_FWHM / 2.
            img = self[..., line_energy - det:line_energy +
                       det].integrate_simpson(-1)
            img.mapped_parameters.title = (
                'Intensity of %s at %.2f %s from %s' %
                (Xray_line, line_energy,
                 self.axes_manager.signal_axes[0].units,
                 self.mapped_parameters.title))
            if img.axes_manager.navigation_dimension >= 2:
                img = img.as_image([0, 1])
            elif img.axes_manager.navigation_dimension == 1:
                img.axes_manager.set_signal_dimension(1)
            if plot_result:
                if img.axes_manager.signal_dimension != 0:
                    img.plot()
                else:
                    print("%s at %s %s : Intensity = %.2f" %
                          (Xray_line, line_energy,
                           self.axes_manager.signal_axes[0].units, img.data))
            intensities.append(img)
        return intensities
Example #21
0
    def get_lines_intensity(self,
                            xray_lines=None,
                            plot_result=False,
                            only_one=True,
                            only_lines=("a", ),
                            **kwargs):
        """
        Return the fitted intensity of the X-ray lines.

        Return the area under the gaussian corresping to the X-ray lines

        Parameters
        ----------
        xray_lines: {None, list of string}
            If None,
            if `metadata.Sample.elements.xray_lines` contains a
            list of lines use those.
            If `metadata.Sample.elements.xray_lines` is undefined
            or empty but `metadata.Sample.elements` is defined,
            use the same syntax as `add_line` to select a subset of lines
            for the operation.
            Alternatively, provide an iterable containing
            a list of valid X-ray lines symbols.
        plot_result : bool
            If True, plot the calculated line intensities. If the current
            object is a single spectrum it prints the result instead.
        only_one : bool
            If False, use all the lines of each element in the data spectral
            range. If True use only the line at the highest energy
            above an overvoltage of 2 (< beam energy / 2).
        only_lines : {None, list of strings}
            If not None, use only the given lines.
        kwargs
            The extra keyword arguments for plotting. See
            `utils.plot.plot_signals`

        Returns
        -------
        intensities : list
            A list containing the intensities as Signal subclasses.

        Examples
        --------
        >>> m.multifit()
        >>> m.get_lines_intensity(["C_Ka", "Ta_Ma"])
        """
        from hyperspy import utils
        intensities = []

        if xray_lines is None:
            xray_lines = [component.name for component in self.xray_lines]
        else:
            xray_lines = self.signal._parse_xray_lines(xray_lines, only_one,
                                                       only_lines)
            xray_lines = list(
                filter(lambda x: x in [a.name for a in self], xray_lines))
        if len(xray_lines) == 0:
            raise ValueError("These X-ray lines are not part of the model.")

        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy = self.signal._get_line_energy(xray_line)
            data_res = self[xray_line].A.map['values']
            if self.axes_manager.navigation_dimension == 0:
                data_res = data_res[0]
            img = self.signal.isig[0:1].integrate1D(-1)
            img.data = data_res
            img.metadata.General.title = (
                'Intensity of %s at %.2f %s from %s' %
                (xray_line, line_energy,
                 self.signal.axes_manager.signal_axes[0].units,
                 self.signal.metadata.General.title))
            img.axes_manager.set_signal_dimension(0)
            if plot_result and img.axes_manager.signal_dimension == 0:
                print(
                    "%s at %s %s : Intensity = %.2f" %
                    (xray_line, line_energy,
                     self.signal.axes_manager.signal_axes[0].units, img.data))
            img.metadata.set_item("Sample.elements", ([element]))
            img.metadata.set_item("Sample.xray_lines", ([xray_line]))
            intensities.append(img)
        if plot_result and img.axes_manager.signal_dimension != 0:
            utils.plot.plot_signals(intensities, **kwargs)
        return intensities
Example #22
0
    def quantification(
        self,
        intensities,
        kfactors,
        composition_units="weight",
        navigation_mask=1.0,
        closing=True,
        plot_result=False,
        **kwargs
    ):
        """
        Quantification of intensities to return elemental composition

        Method: Cliff-Lorimer

        Parameters
        ----------
        intensities: list of signal
            the intensitiy for each X-ray lines.
        kfactors: list of float
            The list of kfactor in same order as intensities. Note that
            intensities provided by hyperspy are sorted by the aplhabetical
            order of the X-ray lines. eg. kfactors =[0.982, 1.32, 1.60] for
            ['Al_Ka','Cr_Ka', 'Ni_Ka'].
        composition_units: 'weight' or 'atomic'
            Quantification returns weight percent. By choosing 'atomic', the
            return composition is in atomic percent.
        navigation_mask : None or float or signal
            The navigation locations marked as True are not used in the
            quantification. If int is given the vacuum_mask method is used to
            generate a mask with the int value as threhsold.
            Else provides a signal with the navigation shape.
        closing: bool
            If true, applied a morphologic closing to the mask obtained by
            vacuum_mask.
        plot_result : bool
            If True, plot the calculated composition. If the current
            object is a single spectrum it prints the result instead.
        kwargs
            The extra keyword arguments are passed to plot.

        Return
        ------
        A list of quantified elemental maps (signal) giving the composition of
        the sample in weight or atomic percent.

        Examples
        --------
        >>> s = utils.example_signals.EDS_TEM_Spectrum()
        >>> s.add_lines()
        >>> kfactors = [1.450226, 5.075602] #For Fe Ka and Pt La
        >>> bw = s.estimate_background_windows(line_width=[5.0, 2.0])
        >>> s.plot(background_windows=bw)
        >>> intensities = s.get_lines_intensity(background_windows=bw)
        >>> res = s.quantification(intensities, kfactors, plot_result=True,
        >>>                        composition_units='atomic')
        Fe (Fe_Ka): Composition = 15.41 atomic percent
        Pt (Pt_La): Composition = 84.59 atomic percent

        See also
        --------
        vacuum_mask
        """
        if isinstance(navigation_mask, float):
            navigation_mask = self.vacuum_mask(navigation_mask, closing).data
        elif navigation_mask is not None:
            navigation_mask = navigation_mask.data
        xray_lines = self.metadata.Sample.xray_lines
        composition = utils.stack(intensities)
        composition.data = (
            utils_eds.quantification_cliff_lorimer(composition.data, kfactors=kfactors, mask=navigation_mask) * 100.0
        )
        composition = composition.split()
        if composition_units == "atomic":
            composition = utils.material.weight_to_atomic(composition)
        for i, xray_line in enumerate(xray_lines):
            element, line = utils_eds._get_element_and_line(xray_line)
            composition[i].metadata.General.title = composition_units + " percent of " + element
            composition[i].metadata.set_item("Sample.elements", ([element]))
            composition[i].metadata.set_item("Sample.xray_lines", ([xray_line]))
            if plot_result and composition[i].axes_manager.signal_dimension == 0:
                print(
                    "%s (%s): Composition = %.2f %s percent"
                    % (element, xray_line, composition[i].data, composition_units)
                )
        if plot_result and composition[i].axes_manager.signal_dimension != 0:
            utils.plot.plot_signals(composition, **kwargs)
        return composition
Example #23
0
    def get_lines_intensity(self,
                            xray_lines=None,
                            plot_result=False,
                            **kwargs):
        """
        Return the fitted intensity of the X-ray lines.

        Return the area under the gaussian corresping to the X-ray lines

        Parameters
        ----------
        xray_lines: list of str or None or 'from_metadata'
            If None, all main X-ray lines (alpha)
            If 'from_metadata', take the Xray_lines stored in the `metadata`
            of the spectrum. Alternatively, provide an iterable containing
            a list of valid X-ray lines symbols.
        plot_result : bool
            If True, plot the calculated line intensities. If the current
            object is a single spectrum it prints the result instead.
        kwargs
            The extra keyword arguments for plotting. See
            `utils.plot.plot_signals`

        Returns
        -------
        intensities : list
            A list containing the intensities as Signal subclasses.

        Examples
        --------
        >>> m.multifit()
        >>> m.get_lines_intensity(["C_Ka", "Ta_Ma"])
        """
        from hyperspy import utils
        intensities = []
        if xray_lines is None:
            xray_lines = [component.name for component in self.xray_lines]
        else:
            if xray_lines == 'from_metadata':
                xray_lines = self.signal.metadata.Sample.xray_lines
            xray_lines = filter(lambda x: x in [a.name for a in self],
                                xray_lines)
        if not xray_lines:
            raise ValueError("These X-ray lines are not part of the model.")
        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy = self.signal._get_line_energy(xray_line)
            data_res = self[xray_line].A.map['values']
            if self.axes_manager.navigation_dimension == 0:
                data_res = data_res[0]
            img = self.signal.isig[0:1].integrate1D(-1)
            img.data = data_res
            img.metadata.General.title = (
                'Intensity of %s at %.2f %s from %s' %
                (xray_line, line_energy,
                 self.signal.axes_manager.signal_axes[0].units,
                 self.signal.metadata.General.title))
            if img.axes_manager.navigation_dimension >= 2:
                img = img.as_signal2D([0, 1])
            elif img.axes_manager.navigation_dimension == 1:
                img.axes_manager.set_signal_dimension(1)
            if plot_result and img.axes_manager.signal_dimension == 0:
                print(
                    "%s at %s %s : Intensity = %.2f" %
                    (xray_line, line_energy,
                     self.signal.axes_manager.signal_axes[0].units, img.data))
            img.metadata.set_item("Sample.elements", ([element]))
            img.metadata.set_item("Sample.xray_lines", ([xray_line]))
            intensities.append(img)
        if plot_result and img.axes_manager.signal_dimension != 0:
            utils.plot.plot_signals(intensities, **kwargs)
        return intensities
Example #24
0
 def on_pick_line(self, line):
     el, _ = _get_element_and_line(line)
     self.picked.emit(el)
Example #25
0
    def get_lines_intensity(self,
                            xray_lines=None,
                            integration_windows=2.,
                            background_windows=None,
                            plot_result=False,
                            only_one=True,
                            only_lines=("a", ),
                            **kwargs):
        """Return the intensity map of selected Xray lines.

        The intensities, the number of X-ray counts, are computed by
        suming the spectrum over the
        different X-ray lines. The sum window width
        is calculated from the energy resolution of the detector
        as defined in 'energy_resolution_MnKa' of the metadata.
        Backgrounds average in provided windows can be subtracted from the
        intensities.

        Parameters
        ----------
        xray_lines: {None, "best", list of string}
            If None,
            if `metadata.Sample.elements.xray_lines` contains a
            list of lines use those.
            If `metadata.Sample.elements.xray_lines` is undefined
            or empty but `metadata.Sample.elements` is defined,
            use the same syntax as `add_line` to select a subset of lines
            for the operation.
            Alternatively, provide an iterable containing
            a list of valid X-ray lines symbols.
        integration_windows: Float or array
            If float, the width of the integration windows is the
            'integration_windows_width' times the calculated FWHM of the line.
            Else provide an array for which each row corresponds to a X-ray
            line. Each row contains the left and right value of the window.
        background_windows: None or 2D array of float
            If None, no background subtraction. Else, the backgrounds average
            in the windows are subtracted from the return intensities.
            'background_windows' provides the position of the windows in
            energy. Each line corresponds to a X-ray line. In a line, the two
            first values correspond to the limits of the left window and the
            two last values correspond to the limits of the right window.
        plot_result : bool
            If True, plot the calculated line intensities. If the current
            object is a single spectrum it prints the result instead.
        only_one : bool
            If False, use all the lines of each element in the data spectral
            range. If True use only the line at the highest energy
            above an overvoltage of 2 (< beam energy / 2).
        only_lines : {None, list of strings}
            If not None, use only the given lines.
        kwargs
            The extra keyword arguments for plotting. See
            `utils.plot.plot_signals`

        Returns
        -------
        intensities : list
            A list containing the intensities as BaseSignal subclasses.

        Examples
        --------
        >>> s = hs.datasets.example_signals.EDS_SEM_Spectrum()
        >>> s.get_lines_intensity(['Mn_Ka'], plot_result=True)
        Mn_La at 0.63316 keV : Intensity = 96700.00

        >>> s = hs.datasets.example_signals.EDS_SEM_Spectrum()
        >>> s.plot(['Mn_Ka'], integration_windows=2.1)
        >>> s.get_lines_intensity(['Mn_Ka'],
        >>>                       integration_windows=2.1, plot_result=True)
        Mn_Ka at 5.8987 keV : Intensity = 53597.00

        >>> s = hs.datasets.example_signals.EDS_SEM_Spectrum()
        >>> s.set_elements(['Mn'])
        >>> s.set_lines(['Mn_Ka'])
        >>> bw = s.estimate_background_windows()
        >>> s.plot(background_windows=bw)
        >>> s.get_lines_intensity(background_windows=bw, plot_result=True)
        Mn_Ka at 5.8987 keV : Intensity = 46716.00

        See also
        --------
        set_elements, add_elements, estimate_background_windows,
        plot

        """

        only_lines = utils_eds._parse_only_lines(only_lines)
        xray_lines = self._get_xray_lines(xray_lines,
                                          only_one=only_one,
                                          only_lines=only_lines)
        xray_lines, xray_not_here = self._get_xray_lines_in_spectral_range(
            xray_lines)
        for xray in xray_not_here:
            warnings.warn("%s is not in the data energy range." % xray +
                          "You can remove it with" +
                          "s.metadata.Sample.xray_lines.remove('%s')" % xray)
        if hasattr(integration_windows, '__iter__') is False:
            integration_windows = self.estimate_integration_windows(
                windows_width=integration_windows, xray_lines=xray_lines)
        intensities = []
        ax = self.axes_manager.signal_axes[0]
        # test Signal1D (0D problem)
        # signal_to_index = self.axes_manager.navigation_dimension - 2
        for i, (Xray_line,
                window) in enumerate(zip(xray_lines, integration_windows)):
            line_energy, line_FWHM = self._get_line_energy(Xray_line,
                                                           FWHM_MnKa='auto')
            element, line = utils_eds._get_element_and_line(Xray_line)
            img = self.isig[window[0]:window[1]].integrate1D(-1)
            if np.issubdtype(img.data.dtype, np.integer):
                # The operations below require a float dtype with the default
                # numpy casting rule ('same_kind')
                img.change_dtype("float")
            if background_windows is not None:
                bw = background_windows[i]
                # TODO: test to prevent slicing bug. To be reomved when fixed
                indexes = [
                    float(ax.value2index(de)) for de in list(bw) + window
                ]
                if indexes[0] == indexes[1]:
                    bck1 = self.isig[bw[0]]
                else:
                    bck1 = self.isig[bw[0]:bw[1]].integrate1D(-1)
                if indexes[2] == indexes[3]:
                    bck2 = self.isig[bw[2]]
                else:
                    bck2 = self.isig[bw[2]:bw[3]].integrate1D(-1)
                corr_factor = (indexes[5] - indexes[4]) / (
                    (indexes[1] - indexes[0]) + (indexes[3] - indexes[2]))
                img = img - (bck1 + bck2) * corr_factor
            img.metadata.General.title = (
                'X-ray line intensity of %s: %s at %.2f %s' % (
                    self.metadata.General.title,
                    Xray_line,
                    line_energy,
                    self.axes_manager.signal_axes[0].units,
                ))
            img.axes_manager.set_signal_dimension(0)
            if plot_result and img.axes_manager.navigation_size == 1:
                print("%s at %s %s : Intensity = %.2f" %
                      (Xray_line, line_energy, ax.units, img.data))
            img.metadata.set_item("Sample.elements", ([element]))
            img.metadata.set_item("Sample.xray_lines", ([Xray_line]))
            intensities.append(img)
        if plot_result and img.axes_manager.navigation_size != 1:
            utils.plot.plot_signals(intensities, **kwargs)
        return intensities
Example #26
0
    def quantification(self,
                       intensities,
                       method,
                       factors='auto',
                       composition_units='atomic',
                       navigation_mask=1.0,
                       closing=True,
                       plot_result=False,
                       **kwargs):
        """
        Quantification using Cliff-Lorimer, the zeta-factor method, or
        ionization cross sections.

        Parameters
        ----------
        intensities: list of signal
            the intensitiy for each X-ray lines.
        method: 'CL' or 'zeta' or 'cross_section'
            Set the quantification method: Cliff-Lorimer, zeta-factor, or
            ionization cross sections.
        factors: list of float
            The list of kfactors, zeta-factors or cross sections in same order as
            intensities. Note that intensities provided by Hyperspy are sorted
            by the alphabetical order of the X-ray lines.
            eg. factors =[0.982, 1.32, 1.60] for ['Al_Ka', 'Cr_Ka', 'Ni_Ka'].
        composition_units: 'weight' or 'atomic'
            The quantification returns the composition in atomic percent by default,
            but can also return weight percent if specified.
        navigation_mask : None or float or signal
            The navigation locations marked as True are not used in the
            quantification. If int is given the vacuum_mask method is used to
            generate a mask with the int value as threhsold.
            Else provides a signal with the navigation shape.
        closing: bool
            If true, applied a morphologic closing to the mask obtained by
            vacuum_mask.
        plot_result : bool
            If True, plot the calculated composition. If the current
            object is a single spectrum it prints the result instead.
        kwargs
            The extra keyword arguments are passed to plot.

        Returns
        ------
        A list of quantified elemental maps (signal) giving the composition of
        the sample in weight or atomic percent.

        If the method is 'zeta' this function also returns the mass thickness
        profile for the data.

        If the method is 'cross_section' this function also returns the atom
        counts for each element.

        Examples
        --------
        >>> s = hs.datasets.example_signals.EDS_TEM_Spectrum()
        >>> s.add_lines()
        >>> kfactors = [1.450226, 5.075602] #For Fe Ka and Pt La
        >>> bw = s.estimate_background_windows(line_width=[5.0, 2.0])
        >>> s.plot(background_windows=bw)
        >>> intensities = s.get_lines_intensity(background_windows=bw)
        >>> res = s.quantification(intensities, kfactors, plot_result=True,
        >>>                        composition_units='atomic')
        Fe (Fe_Ka): Composition = 15.41 atomic percent
        Pt (Pt_La): Composition = 84.59 atomic percent

        See also
        --------
        vacuum_mask
        """
        if isinstance(navigation_mask, float):
            navigation_mask = self.vacuum_mask(navigation_mask, closing).data
        elif navigation_mask is not None:
            navigation_mask = navigation_mask.data
        xray_lines = self.metadata.Sample.xray_lines
        composition = utils.stack(intensities)
        if method == 'CL':
            composition.data = utils_eds.quantification_cliff_lorimer(
                composition.data, kfactors=factors,
                mask=navigation_mask) * 100.
        elif method == 'zeta':
            results = utils_eds.quantification_zeta_factor(
                composition.data, zfactors=factors,
                dose=self._get_dose(method))
            composition.data = results[0] * 100.
            mass_thickness = intensities[0].deepcopy()
            mass_thickness.data = results[1]
            mass_thickness.metadata.General.title = 'Mass thickness'
        elif method == 'cross_section':
            results = utils_eds.quantification_cross_section(composition.data,
                    cross_sections=factors,
                    dose=self._get_dose(method))
            composition.data = results[0] * 100
            number_of_atoms = utils.stack(intensities)
            number_of_atoms.data = results[1]
            number_of_atoms = number_of_atoms.split()
        else:
            raise ValueError ('Please specify method for quantification, as \'CL\', \'zeta\' or \'cross_section\'')
        composition = composition.split()
        if composition_units == 'atomic':
            if method != 'cross_section':
                composition = utils.material.weight_to_atomic(composition)
        else:
            if method == 'cross_section':
                composition = utils.material.atomic_to_weight(composition)
        for i, xray_line in enumerate(xray_lines):
            element, line = utils_eds._get_element_and_line(xray_line)
            composition[i].metadata.General.title = composition_units + \
                ' percent of ' + element
            composition[i].metadata.set_item("Sample.elements", ([element]))
            composition[i].metadata.set_item(
                "Sample.xray_lines", ([xray_line]))
            if plot_result and \
                    composition[i].axes_manager.signal_dimension == 0:
                print("%s (%s): Composition = %.2f %s percent"
                      % (element, xray_line, composition[i].data,
                         composition_units))
        if method=='cross_section':
            for i, xray_line in enumerate(xray_lines):
                element, line = utils_eds._get_element_and_line(xray_line)
                number_of_atoms[i].metadata.General.title = 'atom counts of ' +\
                    element
                number_of_atoms[i].metadata.set_item("Sample.elements",
                    ([element]))
                number_of_atoms[i].metadata.set_item(
                    "Sample.xray_lines", ([xray_line]))
        if plot_result and composition[i].axes_manager.signal_dimension != 0:
            utils.plot.plot_signals(composition, **kwargs)
        if method=='zeta':
            self.metadata.set_item("Sample.mass_thickness", mass_thickness)
            return composition, mass_thickness
        elif method == 'cross_section':
            return composition, number_of_atoms
        elif method == 'CL':
            return composition
        else:
            raise ValueError ('Please specify method for quantification, as \'CL\', \'zeta\' or \'cross_section\'')
Example #27
0
 def on_pick_line(self, line):
     el, _ = _get_element_and_line(line)
     self.picked.emit(el)
Example #28
0
    def quantification(self,
                       intensities,
                       method,
                       factors,
                       composition_units='atomic',
                       navigation_mask=1.0,
                       closing=True,
                       plot_result=False,
                       **kwargs):
        """
        Quantification using Cliff-Lorimer, the zeta-factor method, or
        ionization cross sections.

        Parameters
        ----------
        intensities: list of signal
            the intensitiy for each X-ray lines.
        method: 'CL' or 'zeta' or 'cross_section'
            Set the quantification method: Cliff-Lorimer, zeta-factor, or
            ionization cross sections.
        factors: list of float
            The list of kfactors, zeta-factors or cross sections in same order
            as intensities. Note that intensities provided by Hyperspy are
            sorted by the alphabetical order of the X-ray lines.
            eg. factors =[0.982, 1.32, 1.60] for ['Al_Ka', 'Cr_Ka', 'Ni_Ka'].
        composition_units: 'weight' or 'atomic'
            The quantification returns the composition in atomic percent by
            default, but can also return weight percent if specified.
        navigation_mask : None or float or signal
            The navigation locations marked as True are not used in the
            quantification. If int is given the vacuum_mask method is used to
            generate a mask with the int value as threhsold.
            Else provides a signal with the navigation shape.
        closing: bool
            If true, applied a morphologic closing to the mask obtained by
            vacuum_mask.
        plot_result : bool
            If True, plot the calculated composition. If the current
            object is a single spectrum it prints the result instead.
        kwargs
            The extra keyword arguments are passed to plot.

        Returns
        ------
        A list of quantified elemental maps (signal) giving the composition of
        the sample in weight or atomic percent.

        If the method is 'zeta' this function also returns the mass thickness
        profile for the data.

        If the method is 'cross_section' this function also returns the atom
        counts for each element.

        Examples
        --------
        >>> s = hs.datasets.example_signals.EDS_TEM_Spectrum()
        >>> s.add_lines()
        >>> kfactors = [1.450226, 5.075602] #For Fe Ka and Pt La
        >>> bw = s.estimate_background_windows(line_width=[5.0, 2.0])
        >>> s.plot(background_windows=bw)
        >>> intensities = s.get_lines_intensity(background_windows=bw)
        >>> res = s.quantification(intensities, kfactors, plot_result=True,
        >>>                        composition_units='atomic')
        Fe (Fe_Ka): Composition = 15.41 atomic percent
        Pt (Pt_La): Composition = 84.59 atomic percent

        See also
        --------
        vacuum_mask
        """
        if self.axes_manager.navigation_size == 0:
            navigation_mask = None
        elif isinstance(navigation_mask, float):
            navigation_mask = self.vacuum_mask(navigation_mask, closing).data
        elif navigation_mask is not None:
            navigation_mask = navigation_mask.data

        composition = utils.stack(intensities, lazy=False)
        if method == 'CL':
            composition.data = utils_eds.quantification_cliff_lorimer(
                composition.data, kfactors=factors,
                mask=navigation_mask) * 100.
        elif method == 'zeta':
            results = utils_eds.quantification_zeta_factor(composition.data,
                                                           zfactors=factors,
                                                           dose=self._get_dose(
                                                               method,
                                                               **kwargs))
            composition.data = results[0] * 100.
            mass_thickness = intensities[0].deepcopy()
            mass_thickness.data = results[1]
            mass_thickness.metadata.General.title = 'Mass thickness'
        elif method == 'cross_section':
            results = utils_eds.quantification_cross_section(
                composition.data,
                cross_sections=factors,
                dose=self._get_dose(method, **kwargs))
            composition.data = results[0] * 100
            number_of_atoms = composition._deepcopy_with_new_data(results[1])
            number_of_atoms = number_of_atoms.split()
        else:
            raise ValueError("Please specify method for quantification, "
                             "as 'CL', 'zeta' or 'cross_section'.")

        composition = composition.split()
        if composition_units == 'atomic':
            if method != 'cross_section':
                composition = utils.material.weight_to_atomic(composition)
        else:
            if method == 'cross_section':
                composition = utils.material.atomic_to_weight(composition)
        for i, intensity in enumerate(intensities):
            xray_line = intensity.metadata.Sample.xray_lines[0]
            element, line = utils_eds._get_element_and_line(xray_line)
            composition[i].metadata.General.title = composition_units + \
                ' percent of ' + element
            composition[i].metadata.set_item("Sample.elements", ([element]))
            composition[i].metadata.set_item("Sample.xray_lines",
                                             ([xray_line]))
            if plot_result and \
                    composition[i].axes_manager.navigation_size == 1:
                print("%s (%s): Composition = %.2f %s percent" %
                      (element, xray_line, composition[i].data,
                       composition_units))
            if method == 'cross_section':
                number_of_atoms[i].metadata.General.title = \
                    'atom counts of ' + element
                number_of_atoms[i].metadata.set_item("Sample.elements",
                                                     ([element]))
                number_of_atoms[i].metadata.set_item("Sample.xray_lines",
                                                     ([xray_line]))
        if plot_result and composition[i].axes_manager.navigation_size != 1:
            utils.plot.plot_signals(composition, **kwargs)
        if method == 'zeta':
            self.metadata.set_item("Sample.mass_thickness", mass_thickness)
            return composition, mass_thickness
        elif method == 'cross_section':
            return composition, number_of_atoms
        elif method == 'CL':
            return composition
        else:
            raise ValueError("Please specify method for quantification, as "
                             "'CL', 'zeta' or 'cross_section'.")