import numbers
import numpy as np
import scipy.io as spio
from renishawWiRE import WDFReader
from . import core
from . import utils
from .preprocessing import Pipeline
def _loadmat(filename):
data = spio.loadmat(filename, struct_as_record=False, squeeze_me=True)
for key in data:
if isinstance(data[key], spio.matlab.mat_struct):
data[key] = _todict(data[key])
return data
def _todict(matobj):
"""
A recursive function which constructs from matobjects nested dictionaries.
From: https://stackoverflow.com/questions/7008608/scipy-io-loadmat-nested-structures-i-e-dictionaries
"""
dict = {}
for strg in matobj._fieldnames:
elem = matobj.__dict__[strg]
if isinstance(elem, spio.matlab.mat_struct):
dict[strg] = _todict(elem)
else:
dict[strg] = elem
return dict
def get_value(nested_dict, key):
"""
A recursive function to get the value of a key in a nested dictionary.
"""
for k, v in nested_dict.items():
if k == key:
return v
elif isinstance(v, dict):
p = get_value(v, key)
if p is not None:
return p
[docs]
def witec(
filename: str,
*,
preprocess: Pipeline = None,
laser_excitation: numbers.Number = 532
) -> core.Spectrum or core.SpectralImage:
"""
Loads MATLAB files exported from `WITec's WITec Suite software <https://raman.oxinst.com/products/software/witec-software-suite>`_.
Parameters
----------
filename : str
The name of the MATLAB file to load. Full path or relative to working directory.
preprocess : :class:`~ramanspy.preprocessing.Pipeline`, optional
A preprocessing pipeline to apply to the loaded data. If not specified (default), no preprocessing is applied.
laser_excitation : numeric, optional
The excitation wavelength of the laser (in nm). Default is 532 nm.
Returns
---------
Union[core.Spectrum, core.SpectralImage] :
The loaded data.
Example
----------
.. code::
import ramanspy as rp
# Loading a single spectrum
raman_spectrum = rp.load.witec("path/to/file/witec_spectrum.mat")
# Loading Raman image data
raman_image = rp.load.witec("path/to/file/witec_image.mat")
# Loading volumetric Raman data from a list of Raman image files by stacking them as layers along the z-axis
image_layer_files = ["path/to/file/witec_image_1.mat", ..., "path/to/file/witec_image_n.mat"]
raman_image_stack = [rp.load.witec(image_layer_file) for image_layer_file in image_layer_files]
raman_volume = rp.SpectralVolume.from_image_stack(raman_image_stack)
"""
matlab_dict = _loadmat(filename)
axis = get_value(matlab_dict, 'axisscale')[1]
shift_values = utils.wavelength_to_wavenumber(axis[0], laser_excitation) if axis[1] != 'rel. 1/cm' else axis[0]
spectral_data = get_value(matlab_dict, 'data')
if len(spectral_data.shape) == 1: # i.e. single spectrum
obj = core.Spectrum(spectral_data, shift_values)
elif len(spectral_data.shape) == 2:
imagesize = get_value(matlab_dict, 'imagesize')
spectral_data = spectral_data.reshape(imagesize[1], imagesize[0], -1).transpose(1, 0, 2)
obj = core.SpectralImage(spectral_data, shift_values)
else:
raise ValueError(
f"Raman Matlab type {get_value(matlab_dict, 'type')} and dimension {len(spectral_data.shape)} is unknown")
if preprocess is not None:
obj = preprocess.apply(obj)
return obj
[docs]
def ocean_insight(filename: str, *, preprocess: Pipeline = None, laser_excitation: numbers.Number = 532) -> core.Spectrum:
"""
Loads spectra data from `Ocean Insight's OceanView software <https://www.oceaninsight.com/products/software/>`_ .txt files.
Parameters
----------
filename : str
The name of the .txt file to load. Full path or relative to working directory.
preprocess : :class:`~ramanspy.preprocessing.Pipeline`, optional
A preprocessing pipeline to apply to the loaded data. If not specified (default), no preprocessing is applied.
laser_excitation : numeric, optional
The excitation wavelength of the laser (in nm). Default is 532 nm.
Returns
---------
core.Spectrum :
The loaded data.
Example
----------
.. code::
import ramanspy as rp
# Loading a single spectrum
raman_spectrum = rp.load.ocean_insight("path/to/file/ocean_insight_spectrum.txt")
"""
region = "metadata"
metadata = {}
# metadata["filename"] = file_name
data = []
with open(filename) as f:
for line in f:
line = line.strip()
if line.startswith(" >>"):
region = "data"
continue
if region == "metadata":
k, v = line.split(": ")
metadata[k] = v
continue
data.append(line)
spectral_data = data[:, 1]
shift_values = data[:, 0]
if metadata["XAxis mode"].lower() == "wavelengths":
shift_values = utils.wavelength_to_wavenumber(shift_values, laser_excitation)
spectrum = core.Spectrum(spectral_data, shift_values)
if preprocess is not None:
spectrum = preprocess.apply(spectrum)
return spectrum
[docs]
def renishaw(filename: str, *, preprocess: Pipeline = None) -> core.SpectralContainer or core.Spectrum or core.SpectralImage:
"""
Loads spectra data from `Ranishaw's WiRE software <https://www.renishaw.com/en/raman-software--9450>`_ .wdf files.
Parameters
----------
filename : str
The name of the .wdf file to load. Full path or relative to working directory.
preprocess : :class:`~ramanspy.preprocessing.Pipeline`, optional
A preprocessing pipeline to apply to the loaded data. If not specified (default), no preprocessing is applied.
Returns
---------
Union[core.SpectralContainer, core.Spectrum, core.SpectralImage] :
The loaded data.
.. note:: Implementation based on `renishawWiRE <https://pypi.org/project/renishawWiRE/>`_.
Example
----------
.. code::
import ramanspy as rp
raman_spectrum = rp.load.renishaw("path/to/file/wire_data.wdf")
"""
reader = WDFReader(filename)
if len(reader.spectra.shape) == 1:
obj = core.Spectrum(reader.spectra, reader.xdata)
elif len(reader.spectra.shape) == 3:
obj = core.SpectralImage(reader.spectra, reader.xdata)
else:
obj = core.SpectralContainer(reader.spectra, reader.xdata)
if preprocess is not None:
obj = preprocess.apply(obj)
return obj
def opus(filename: str, *, preprocess: Pipeline = None) -> core.Spectrum:
"""
Loads spectra data from `Bruker's OPUS software <https://www.bruker.com/en/products-and-solutions/infrared-and-raman/opus-spectroscopy-software.html>`_ files.
Parameters
----------
filename : str
The name of the file to load. Full path or relative to working directory.
preprocess : :class:`~ramanspy.preprocessing.Pipeline`, optional
A preprocessing pipeline to apply to the loaded data. If not specified (default), no preprocessing is applied.
Returns
---------
core.Spectrum :
The loaded data.
.. warning:: The function has not been implemented yet.
Example
----------
.. code::
import ramanspy as rp
# Loading a single spectrum
raman_spectrum = rp.load.opus("path/to/file/ocean_insight_spectrum.O00")
"""
raise NotImplemented()
[docs]
def labspec(filename: str, *, preprocess: Pipeline = None) -> core.SpectralContainer or core.Spectrum:
"""
Loads spectra data from `HORIBA's LabSpec software <https://www.horiba.com/int/scientific/products/detail/action/show/Product/labspec-6-spectroscopy-suite-software-1843/>`_ .txt files.
Parameters
----------
filename : str
The name of the .txt file to load. Full path or relative to working directory.
preprocess : :class:`~ramanspy.preprocessing.Pipeline`, optional
A preprocessing pipeline to apply to the loaded data. If not specified (default), no preprocessing is applied.
Returns
---------
core.SpectralContainer or core.Spectrum:
The loaded data.
Example
----------
.. code::
import ramanspy as rp
# Loading Raman data from labspec
raman_object = rp.load.labspec("path/to/file/ocean_insight_spectrum.txtO")
"""
metadata = {}
data = []
with open(filename) as f:
for line in f:
line = line.strip()
if line.startswith('#'):
k, v = line.split("=")
metadata[k] = v
continue
data.append(line)
data = np.genfromtxt(data, delimiter="\t")
if data.shape[1] == 2:
obj = core.Spectrum(data[:, 1], data[:, 0])
else:
obj = core.SpectralContainer(data[1:, 1:], data[0, 1:])
if preprocess is not None:
obj = preprocess.apply(obj)
return obj