def assign_signal_subclass(dtype, signal_dimension, signal_type="", lazy=False): """Given record_by and signal_type return the matching Signal subclass. Parameters ---------- dtype : :class:`~.numpy.dtype` signal_dimension: int signal_type : {None, "electron_diffraction", "diffraction_profile", "diffraction_vectors", "crystallographic_map", str} lazy: bool Returns ------- Signal or subclass """ # TODO: This method needs to be re-written for pyXem signals! import hyperspy._lazy_signals from hyperspy.signal import BaseSignal # Check if parameter values are allowed: if np.issubdtype(dtype, np.complexfloating): dtype = 'complex' elif ('float' in dtype.name or 'int' in dtype.name or 'void' in dtype.name or 'bool' in dtype.name or 'object' in dtype.name): dtype = 'real' else: raise ValueError('Data type "{}" not understood!'.format(dtype.name)) if not isinstance(signal_dimension, int) or signal_dimension < 0: raise ValueError("signal_dimension must be a positive interger") base_signals = find_subclasses(hyperspy.signals, BaseSignal) lazy_signals = find_subclasses(hyperspy._lazy_signals, hyperspy._lazy_signals.LazySignal) if lazy: signals = lazy_signals else: signals = { k: v for k, v in base_signals.items() if k not in lazy_signals} dtype_matches = [s for s in signals.values() if dtype == s._dtype] dtype_dim_matches = [s for s in dtype_matches if signal_dimension == s._signal_dimension] dtype_dim_type_matches = [s for s in dtype_dim_matches if signal_type == s._signal_type or signal_type in s._alias_signal_types] if dtype_dim_type_matches: # Perfect match found, return it. return dtype_dim_type_matches[0] elif [s for s in dtype_dim_matches if s._signal_type == ""]: # just signal_dimension and dtype matches # Return a general class for the given signal dimension. return [s for s in dtype_dim_matches if s._signal_type == ""][0] else: # no signal_dimension match either, hence return the general subclass for # correct dtype return [s for s in dtype_matches if s._signal_dimension == - 1 and s._signal_type == ""][0]
# This file is part of HyperSpy. # # HyperSpy is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # HyperSpy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with HyperSpy. If not, see <http://www.gnu.org/licenses/>. import numpy as np import pytest import hyperspy.signals from hyperspy.misc.utils import find_subclasses from hyperspy.signal import BaseSignal @pytest.mark.parametrize("signal", find_subclasses(hyperspy.signals, BaseSignal)) def test_lazy_signal_inheritance(signal): bs = getattr(hyperspy.signals, signal) s = bs(np.empty((2, ) * bs._signal_dimension)) ls = s.as_lazy() assert isinstance(ls, bs)
def assign_signal_subclass(dtype, signal_dimension, signal_type='', lazy=False): """Given record_by and signal_type return the matching signal subclass. Parameters ---------- dtype : :class:`~.numpy.dtype` signal_dimension : int signal_type : {'', 'EBSD', 'RadonTransform', str}, optional lazy : bool, optional Returns ------- Signal or subclass """ import kikuchipy.signals import kikuchipy.lazy_signals from hyperspy.signal import BaseSignal from hyperspy.signals import Signal1D, Signal2D from hyperspy._lazy_signals import LazySignal, LazySignal1D, LazySignal2D # Check if parameter values are allowed: if np.issubdtype(dtype, np.complexfloating): dtype = 'complex' elif ('float' in dtype.name or 'int' in dtype.name or 'void' in dtype.name or 'bool' in dtype.name or 'object' in dtype.name): dtype = 'real' else: raise ValueError("Data type '{}' not understood.".format(dtype.name)) if not isinstance(signal_dimension, int) or signal_dimension < 0: raise ValueError("signal_dimension must be a positive integer.") base_signals = find_subclasses(kikuchipy.signals, BaseSignal) lazy_signals = find_subclasses(kikuchipy.lazy_signals, LazySignal) # Add HyperSpy's BaseSignal, Signal1D, Signal2D and their lazy partners for # when signal_type = '' base_signals.update({ 'BaseSignal': BaseSignal, 'Signal1D': Signal1D, 'Signal2D': Signal2D }) lazy_signals.update({ 'LazySignal1D': LazySignal1D, 'LazySignal2D': LazySignal2D }) if lazy: signals = lazy_signals else: signals = { k: v for k, v in base_signals.items() if k not in lazy_signals } dtype_matches = [s for s in signals.values() if dtype == s._dtype] dtype_dim_matches = [ s for s in dtype_matches if signal_dimension == s._signal_dimension ] dtype_dim_type_matches = [ s for s in dtype_dim_matches if signal_type == s._signal_type or signal_type in s._alias_signal_types ] if dtype_dim_type_matches: # Perfect match found, return it return dtype_dim_type_matches[0] elif [s for s in dtype_dim_matches if s._signal_type == '']: # Just signal_dimension and dtype matches # Return a general class for the given signal dimension return [s for s in dtype_dim_matches if s._signal_type == ''][0] else: # No signal_dimension match either, hence return the general subclass # for correct dtype return [ s for s in dtype_matches if s._signal_dimension == -1 and s._signal_type == '' ][0]
def _assign_signal_subclass( dtype: np.dtype, signal_dimension: int, signal_type: str = "", lazy: bool = False, ): """Given ``record_by`` and ``signal_type`` return the matching signal subclass. This function is a modified version of :func:`hyperspy.io.assign_signal_subclass`. Parameters ---------- dtype Data type of signal data. signal_dimension Number of signal dimensions. signal_type Signal type. Options are ""/"EBSD"/"EBSDMasterPattern". lazy Open the data lazily without actually reading the data from disk until required. Allows opening arbitrary sized datasets. Default is False. Returns ------- Signal or subclass """ # Check if parameter values are allowed if ( "float" in dtype.name or "int" in dtype.name or "void" in dtype.name or "bool" in dtype.name or "object" in dtype.name ): dtype = "real" else: raise ValueError(f"Data type '{dtype.name}' not understood.") if not isinstance(signal_dimension, int) or signal_dimension < 0: raise ValueError( "Signal dimension must be a positive integer and not " f"'{signal_dimension}'." ) # Get possible signal classes signals = { key: value for key, value in find_subclasses(kikuchipy.signals, BaseSignal).items() if value._lazy == lazy } # Get signals matching both input signal's dtype and signal dimension dtype_matches = [s for s in signals.values() if s._dtype == dtype] dtype_dim_matches = [ s for s in dtype_matches if s._signal_dimension == signal_dimension ] dtype_dim_type_matches = [ s for s in dtype_dim_matches if signal_type == s._signal_type or signal_type in s._alias_signal_types ] if len(dtype_dim_type_matches) == 1: matches = dtype_dim_type_matches else: raise ValueError( f"No kikuchipy signals match dtype '{dtype}', signal dimension " f"'{signal_dimension}' and signal_type '{signal_type}'." ) return matches[0]
import numpy as np import pytest from hyperspy.misc.utils import find_subclasses from hyperspy.signal import BaseSignal import hyperspy.signals @pytest.mark.parametrize("signal", find_subclasses(hyperspy.signals, BaseSignal)) def test_lazy_signal_inheritance(signal): bs = getattr(hyperspy.signals, signal) s = bs(np.empty((2,) * bs._signal_dimension)) ls = s.as_lazy() assert isinstance(ls, bs)