Module qudi_hira_analysis.measurement_dataclass
Expand source code
from __future__ import annotations
import logging
import re
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Callable
import pandas as pd
from PIL import Image
if TYPE_CHECKING:
import datetime
from pathlib import Path
import lmfit
import numpy as np
logging.basicConfig(format='%(name)s :: %(levelname)s :: %(message)s',
level=logging.INFO)
@dataclass
class PulsedMeasurement:
""" Dataclass for storing pulsed data and metadata """
filepath: Path
loaders: (Callable, Callable) = field(default=None)
__data: pd.DataFrame = field(default=None)
__params: dict = field(default=None)
@property
def data(self) -> pd.DataFrame:
""" Read measurement data from file into pandas DataFrame """
if self.__data is None:
self.__data = self.loaders[0](self.filepath)
return self.__data
@property
def params(self) -> dict:
""" Read measurement params from file into dict """
if self.__params is None:
self.__params = self.loaders[1](self.filepath)
return self.__params
@dataclass
class LaserPulses:
""" Dataclass for storing laser pulses data and metadata """
filepath: Path
loaders: (Callable, Callable) = field(default=None)
__data: np.ndarray = field(default=None)
__params: dict = field(default=None)
@property
def data(self) -> np.ndarray:
""" Read measurement data from file into pandas DataFrame """
if self.__data is None:
self.__data = self.loaders[0](self.filepath)
return self.__data
@property
def params(self) -> dict:
""" Read measurement params from file into dict """
if self.__params is None:
self.__params = self.loaders[1](self.filepath)
return self.__params
@dataclass
class RawTimetrace:
""" Dataclass for storing raw timetrace data and metadata """
filepath: Path
loaders: (Callable, Callable) = field(default=None)
__data: np.ndarray = field(default=None)
__params: dict = field(default=None)
@property
def data(self) -> np.ndarray:
""" Read measurement data from file into pandas DataFrame """
if self.__data is None:
self.__data = self.loaders[0](self.filepath)
return self.__data
@property
def params(self) -> dict:
""" Read measurement params from file into dict """
if self.__params is None:
self.__params = self.loaders[1](self.filepath)
return self.__params
@dataclass
class PulsedMeasurementDataclass:
""" Dataclass for storing pulsed measurement data and metadata """
measurement: PulsedMeasurement
laser_pulses: LaserPulses = field(default=None)
timetrace: RawTimetrace = field(default=None)
def __post_init__(self):
self.base_filename = self.measurement.filepath.name.replace(
"_pulsed_measurement.dat", "")
def show_image(self) -> Image:
""" Use PIL to open the measurement image saved on the disk """
return Image.open(
str(self.measurement.filepath).replace(".dat","_fig.png"))
@dataclass
class MeasurementDataclass:
""" Dataclass for storing measurement data and metadata """
timestamp: datetime.datetime
filepath: Path = field(default=None)
_loaders: (Callable, Callable) = field(default=None)
pulsed: PulsedMeasurementDataclass = field(default=None)
__data: np.ndarray | pd.DataFrame = field(default=None)
__params: dict = field(default=None)
_fit_data: pd.DataFrame = field(default=None)
_fit_model: lmfit.Model = field(default=None)
_xy_position: tuple[int, int] = field(default=None)
def __post_init__(self):
self.log = logging.getLogger(__name__)
if self.pulsed:
self.filename = self.pulsed.base_filename
else:
self.filename = self.filepath.name
def __repr__(self) -> str:
return (f"MeasurementDataclass(timestamp='{self.timestamp}', "
f"filename='{self.filename}')")
@property
def data(self) -> np.ndarray | pd.DataFrame:
""" Read measurement data from file. """
if self.pulsed:
return self.pulsed.measurement.data
else:
if self.__data is None:
self.__data = self._loaders[0](self.filepath)
return self.__data
@property
def params(self) -> dict:
""" Read measurement params from file. """
if self.pulsed:
return self.pulsed.measurement.params
else:
if self.__params is None:
self.__params = self._loaders[1](self.filepath)
return self.__params
@property
def fit_data(self) -> pd.DataFrame:
""" Fit data to a model """
return self._fit_data
@fit_data.setter
def fit_data(self, fit_data: pd.DataFrame):
""" Fit data to a model """
self._fit_data = fit_data
@property
def fit_model(self) -> lmfit.Model:
""" lmfit data model """
return self._fit_model
@fit_model.setter
def fit_model(self, fit_model: lmfit.Model):
self._fit_model = fit_model
@property
def xy_position(self) -> tuple[int, int]:
""" (row, col) position of measurement in image """
return self._xy_position
@xy_position.setter
def xy_position(self, xy_position: tuple[int, int]):
self._xy_position = xy_position
def get_param_from_filename(self, unit: str) -> float | None:
"""
Extract param from filename with format <param><unit>, where param
is a float or integer and unit is a string. The param can be negative
with keyword 'minus' or a decimal point with keyword 'point'.
Args:
unit: unit of param to extract, e.g. dBm, mbar, V etc.
Returns:
Extracted param from filename
Examples:
filename = "rabi_12dBm"
>>> get_param_from_filename(unit='dBm')
12.0
filename = "pixelscan_minus100nm"
>>> get_param_from_filename(unit='dBm')
-100.0
filename = "rabi_2e-6mbar"
>>> get_param_from_filename(unit='mbar')
2e-6
filename = "rabi_2point3uW"
>>> get_param_from_filename(unit='uW')
2.5
"""
filename = self.filename
filename = filename.replace("point", ".")
filename = filename.replace("minus", "-")
params = re.search(rf"(-?\d+\.?\d*)(?={unit})", filename)
if params:
# Handle exponents in filename
if filename[params.start() - 1] == "e":
try:
params = re.search(
rf"(-?_\d)[^a]+?(?={unit})", filename
).group(0)[1:]
return float(params)
except AttributeError as exc:
raise Exception(
f"Parameter with unit '{unit}' not found in "
f"filename '{filename}'"
) from exc
else:
return float(params.group(0))
else:
self.log.warning(f"Unable to extract parameter from filename: {filename}")
return None
def set_datetime_index(self) -> pd.DataFrame:
if 'Start counting time' not in self.__params:
raise ValueError("'Start counting time' not in params")
if not isinstance(self.__data, pd.DataFrame):
raise TypeError("data is not of type pd.DataFrame")
if "Time (s)" not in self.__data.columns:
raise IndexError("Unable to find column 'Time (s)' in DataFrame")
self.__data['Time (s)'] += self.__params['Start counting time'].timestamp()
self.__data["Time"] = pd.to_datetime(self.__data['Time (s)'], unit='s',
utc=True)
self.__data.set_index(self.__data["Time"], inplace=True)
self.__data.tz_convert('Europe/Berlin')
self.__data.drop(["Time", "Time (s)"], inplace=True, axis=1)
return self.__data
Classes
class LaserPulses (filepath: Path, loaders: (Callable, Callable) = None)
-
Dataclass for storing laser pulses data and metadata
Expand source code
@dataclass class LaserPulses: """ Dataclass for storing laser pulses data and metadata """ filepath: Path loaders: (Callable, Callable) = field(default=None) __data: np.ndarray = field(default=None) __params: dict = field(default=None) @property def data(self) -> np.ndarray: """ Read measurement data from file into pandas DataFrame """ if self.__data is None: self.__data = self.loaders[0](self.filepath) return self.__data @property def params(self) -> dict: """ Read measurement params from file into dict """ if self.__params is None: self.__params = self.loaders[1](self.filepath) return self.__params
Class variables
var filepath : Path
var loaders : (Callable, Callable)
Instance variables
var data : np.ndarray
-
Read measurement data from file into pandas DataFrame
Expand source code
@property def data(self) -> np.ndarray: """ Read measurement data from file into pandas DataFrame """ if self.__data is None: self.__data = self.loaders[0](self.filepath) return self.__data
var params : dict
-
Read measurement params from file into dict
Expand source code
@property def params(self) -> dict: """ Read measurement params from file into dict """ if self.__params is None: self.__params = self.loaders[1](self.filepath) return self.__params
class MeasurementDataclass (timestamp: datetime.datetime, filepath: Path = None, pulsed: PulsedMeasurementDataclass = None)
-
Dataclass for storing measurement data and metadata
Expand source code
@dataclass class MeasurementDataclass: """ Dataclass for storing measurement data and metadata """ timestamp: datetime.datetime filepath: Path = field(default=None) _loaders: (Callable, Callable) = field(default=None) pulsed: PulsedMeasurementDataclass = field(default=None) __data: np.ndarray | pd.DataFrame = field(default=None) __params: dict = field(default=None) _fit_data: pd.DataFrame = field(default=None) _fit_model: lmfit.Model = field(default=None) _xy_position: tuple[int, int] = field(default=None) def __post_init__(self): self.log = logging.getLogger(__name__) if self.pulsed: self.filename = self.pulsed.base_filename else: self.filename = self.filepath.name def __repr__(self) -> str: return (f"MeasurementDataclass(timestamp='{self.timestamp}', " f"filename='{self.filename}')") @property def data(self) -> np.ndarray | pd.DataFrame: """ Read measurement data from file. """ if self.pulsed: return self.pulsed.measurement.data else: if self.__data is None: self.__data = self._loaders[0](self.filepath) return self.__data @property def params(self) -> dict: """ Read measurement params from file. """ if self.pulsed: return self.pulsed.measurement.params else: if self.__params is None: self.__params = self._loaders[1](self.filepath) return self.__params @property def fit_data(self) -> pd.DataFrame: """ Fit data to a model """ return self._fit_data @fit_data.setter def fit_data(self, fit_data: pd.DataFrame): """ Fit data to a model """ self._fit_data = fit_data @property def fit_model(self) -> lmfit.Model: """ lmfit data model """ return self._fit_model @fit_model.setter def fit_model(self, fit_model: lmfit.Model): self._fit_model = fit_model @property def xy_position(self) -> tuple[int, int]: """ (row, col) position of measurement in image """ return self._xy_position @xy_position.setter def xy_position(self, xy_position: tuple[int, int]): self._xy_position = xy_position def get_param_from_filename(self, unit: str) -> float | None: """ Extract param from filename with format <param><unit>, where param is a float or integer and unit is a string. The param can be negative with keyword 'minus' or a decimal point with keyword 'point'. Args: unit: unit of param to extract, e.g. dBm, mbar, V etc. Returns: Extracted param from filename Examples: filename = "rabi_12dBm" >>> get_param_from_filename(unit='dBm') 12.0 filename = "pixelscan_minus100nm" >>> get_param_from_filename(unit='dBm') -100.0 filename = "rabi_2e-6mbar" >>> get_param_from_filename(unit='mbar') 2e-6 filename = "rabi_2point3uW" >>> get_param_from_filename(unit='uW') 2.5 """ filename = self.filename filename = filename.replace("point", ".") filename = filename.replace("minus", "-") params = re.search(rf"(-?\d+\.?\d*)(?={unit})", filename) if params: # Handle exponents in filename if filename[params.start() - 1] == "e": try: params = re.search( rf"(-?_\d)[^a]+?(?={unit})", filename ).group(0)[1:] return float(params) except AttributeError as exc: raise Exception( f"Parameter with unit '{unit}' not found in " f"filename '{filename}'" ) from exc else: return float(params.group(0)) else: self.log.warning(f"Unable to extract parameter from filename: {filename}") return None def set_datetime_index(self) -> pd.DataFrame: if 'Start counting time' not in self.__params: raise ValueError("'Start counting time' not in params") if not isinstance(self.__data, pd.DataFrame): raise TypeError("data is not of type pd.DataFrame") if "Time (s)" not in self.__data.columns: raise IndexError("Unable to find column 'Time (s)' in DataFrame") self.__data['Time (s)'] += self.__params['Start counting time'].timestamp() self.__data["Time"] = pd.to_datetime(self.__data['Time (s)'], unit='s', utc=True) self.__data.set_index(self.__data["Time"], inplace=True) self.__data.tz_convert('Europe/Berlin') self.__data.drop(["Time", "Time (s)"], inplace=True, axis=1) return self.__data
Class variables
var filepath : Path
var pulsed : PulsedMeasurementDataclass
var timestamp : datetime.datetime
Instance variables
var data : np.ndarray | pd.DataFrame
-
Read measurement data from file.
Expand source code
@property def data(self) -> np.ndarray | pd.DataFrame: """ Read measurement data from file. """ if self.pulsed: return self.pulsed.measurement.data else: if self.__data is None: self.__data = self._loaders[0](self.filepath) return self.__data
var fit_data : pandas.core.frame.DataFrame
-
Fit data to a model
Expand source code
@property def fit_data(self) -> pd.DataFrame: """ Fit data to a model """ return self._fit_data
var fit_model : lmfit.Model
-
lmfit data model
Expand source code
@property def fit_model(self) -> lmfit.Model: """ lmfit data model """ return self._fit_model
var params : dict
-
Read measurement params from file.
Expand source code
@property def params(self) -> dict: """ Read measurement params from file. """ if self.pulsed: return self.pulsed.measurement.params else: if self.__params is None: self.__params = self._loaders[1](self.filepath) return self.__params
var xy_position : tuple[int, int]
-
(row, col) position of measurement in image
Expand source code
@property def xy_position(self) -> tuple[int, int]: """ (row, col) position of measurement in image """ return self._xy_position
Methods
def get_param_from_filename(self, unit: str) ‑> float | None
-
Extract param from filename with format
, where param is a float or integer and unit is a string. The param can be negative with keyword 'minus' or a decimal point with keyword 'point'. Args
unit
- unit of param to extract, e.g. dBm, mbar, V etc.
Returns
Extracted param from filename
Examples
filename = "rabi_12dBm"
>>> get_param_from_filename(unit='dBm') 12.0
filename = "pixelscan_minus100nm"
>>> get_param_from_filename(unit='dBm') -100.0
filename = "rabi_2e-6mbar"
>>> get_param_from_filename(unit='mbar') 2e-6
filename = "rabi_2point3uW"
>>> get_param_from_filename(unit='uW') 2.5
Expand source code
def get_param_from_filename(self, unit: str) -> float | None: """ Extract param from filename with format <param><unit>, where param is a float or integer and unit is a string. The param can be negative with keyword 'minus' or a decimal point with keyword 'point'. Args: unit: unit of param to extract, e.g. dBm, mbar, V etc. Returns: Extracted param from filename Examples: filename = "rabi_12dBm" >>> get_param_from_filename(unit='dBm') 12.0 filename = "pixelscan_minus100nm" >>> get_param_from_filename(unit='dBm') -100.0 filename = "rabi_2e-6mbar" >>> get_param_from_filename(unit='mbar') 2e-6 filename = "rabi_2point3uW" >>> get_param_from_filename(unit='uW') 2.5 """ filename = self.filename filename = filename.replace("point", ".") filename = filename.replace("minus", "-") params = re.search(rf"(-?\d+\.?\d*)(?={unit})", filename) if params: # Handle exponents in filename if filename[params.start() - 1] == "e": try: params = re.search( rf"(-?_\d)[^a]+?(?={unit})", filename ).group(0)[1:] return float(params) except AttributeError as exc: raise Exception( f"Parameter with unit '{unit}' not found in " f"filename '{filename}'" ) from exc else: return float(params.group(0)) else: self.log.warning(f"Unable to extract parameter from filename: {filename}") return None
def set_datetime_index(self) ‑> pandas.core.frame.DataFrame
-
Expand source code
def set_datetime_index(self) -> pd.DataFrame: if 'Start counting time' not in self.__params: raise ValueError("'Start counting time' not in params") if not isinstance(self.__data, pd.DataFrame): raise TypeError("data is not of type pd.DataFrame") if "Time (s)" not in self.__data.columns: raise IndexError("Unable to find column 'Time (s)' in DataFrame") self.__data['Time (s)'] += self.__params['Start counting time'].timestamp() self.__data["Time"] = pd.to_datetime(self.__data['Time (s)'], unit='s', utc=True) self.__data.set_index(self.__data["Time"], inplace=True) self.__data.tz_convert('Europe/Berlin') self.__data.drop(["Time", "Time (s)"], inplace=True, axis=1) return self.__data
class PulsedMeasurement (filepath: Path, loaders: (Callable, Callable) = None)
-
Dataclass for storing pulsed data and metadata
Expand source code
@dataclass class PulsedMeasurement: """ Dataclass for storing pulsed data and metadata """ filepath: Path loaders: (Callable, Callable) = field(default=None) __data: pd.DataFrame = field(default=None) __params: dict = field(default=None) @property def data(self) -> pd.DataFrame: """ Read measurement data from file into pandas DataFrame """ if self.__data is None: self.__data = self.loaders[0](self.filepath) return self.__data @property def params(self) -> dict: """ Read measurement params from file into dict """ if self.__params is None: self.__params = self.loaders[1](self.filepath) return self.__params
Class variables
var filepath : Path
var loaders : (Callable, Callable)
Instance variables
var data : pandas.core.frame.DataFrame
-
Read measurement data from file into pandas DataFrame
Expand source code
@property def data(self) -> pd.DataFrame: """ Read measurement data from file into pandas DataFrame """ if self.__data is None: self.__data = self.loaders[0](self.filepath) return self.__data
var params : dict
-
Read measurement params from file into dict
Expand source code
@property def params(self) -> dict: """ Read measurement params from file into dict """ if self.__params is None: self.__params = self.loaders[1](self.filepath) return self.__params
class PulsedMeasurementDataclass (measurement: PulsedMeasurement, laser_pulses: LaserPulses = None, timetrace: RawTimetrace = None)
-
Dataclass for storing pulsed measurement data and metadata
Expand source code
@dataclass class PulsedMeasurementDataclass: """ Dataclass for storing pulsed measurement data and metadata """ measurement: PulsedMeasurement laser_pulses: LaserPulses = field(default=None) timetrace: RawTimetrace = field(default=None) def __post_init__(self): self.base_filename = self.measurement.filepath.name.replace( "_pulsed_measurement.dat", "") def show_image(self) -> Image: """ Use PIL to open the measurement image saved on the disk """ return Image.open( str(self.measurement.filepath).replace(".dat","_fig.png"))
Class variables
var laser_pulses : LaserPulses
var measurement : PulsedMeasurement
var timetrace : RawTimetrace
Methods
def show_image(self) ‑>
-
Use PIL to open the measurement image saved on the disk
Expand source code
def show_image(self) -> Image: """ Use PIL to open the measurement image saved on the disk """ return Image.open( str(self.measurement.filepath).replace(".dat","_fig.png"))
class RawTimetrace (filepath: Path, loaders: (Callable, Callable) = None)
-
Dataclass for storing raw timetrace data and metadata
Expand source code
@dataclass class RawTimetrace: """ Dataclass for storing raw timetrace data and metadata """ filepath: Path loaders: (Callable, Callable) = field(default=None) __data: np.ndarray = field(default=None) __params: dict = field(default=None) @property def data(self) -> np.ndarray: """ Read measurement data from file into pandas DataFrame """ if self.__data is None: self.__data = self.loaders[0](self.filepath) return self.__data @property def params(self) -> dict: """ Read measurement params from file into dict """ if self.__params is None: self.__params = self.loaders[1](self.filepath) return self.__params
Class variables
var filepath : Path
var loaders : (Callable, Callable)
Instance variables
var data : np.ndarray
-
Read measurement data from file into pandas DataFrame
Expand source code
@property def data(self) -> np.ndarray: """ Read measurement data from file into pandas DataFrame """ if self.__data is None: self.__data = self.loaders[0](self.filepath) return self.__data
var params : dict
-
Read measurement params from file into dict
Expand source code
@property def params(self) -> dict: """ Read measurement params from file into dict """ if self.__params is None: self.__params = self.loaders[1](self.filepath) return self.__params