From 462290272d8aaabadf8dfded30f1b16208132b4f Mon Sep 17 00:00:00 2001 From: dineshpinto Date: Sat, 30 Sep 2023 01:09:14 +0200 Subject: [PATCH] Regenerate docs --- docs/qudi_hira_analysis/analysis_logic.html | 379 +++++++------ docs/qudi_hira_analysis/data_handler.html | 252 ++++++--- docs/qudi_hira_analysis/helper_functions.html | 51 +- docs/qudi_hira_analysis/index.html | 513 +++++++++++------- docs/qudi_hira_analysis/io_handler.html | 127 +++-- .../measurement_dataclass.html | 93 ++-- 6 files changed, 872 insertions(+), 543 deletions(-) diff --git a/docs/qudi_hira_analysis/analysis_logic.html b/docs/qudi_hira_analysis/analysis_logic.html index 7714016..d5fba76 100644 --- a/docs/qudi_hira_analysis/analysis_logic.html +++ b/docs/qudi_hira_analysis/analysis_logic.html @@ -32,29 +32,32 @@

Module qudi_hira_analysis.analysis_logic

import random import re from itertools import product -from typing import Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np import pandas as pd -from joblib import Parallel, delayed, cpu_count +from joblib import Parallel, cpu_count, delayed from tqdm import tqdm import qudi_hira_analysis._raster_odmr_fitting as rof from qudi_hira_analysis._qudi_fit_logic import FitLogic if TYPE_CHECKING: - from lmfit import Model, Parameters, Parameter + from lmfit import Model, Parameter, Parameters from lmfit.model import ModelResult + from .measurement_dataclass import MeasurementDataclass -logging.basicConfig(format='%(name)s :: %(levelname)s :: %(message)s', level=logging.INFO) +logging.basicConfig(format='%(name)s :: %(levelname)s :: %(message)s', + level=logging.INFO) class FitMethodsAndEstimators: """ Class for storing fit methods and estimators. Fit methods are stored as tuples of (method, estimator) - where method is the name of the fit method and estimator is the name of the estimator. + where method is the name of the fit method and estimator is the name of the + estimator. The fit functions available are: @@ -105,7 +108,7 @@

Module qudi_hira_analysis.analysis_logic

sinetriple: tuple = ("sinetriple", "generic") sinetriplewithexpdecay: tuple = ("sinetriplewithexpdecay", "generic") sinetriplewiththreeexpdecay: tuple = ("sinetriplewiththreeexpdecay", "generic") - twoDgaussian: tuple = ("twoDgaussian", "generic") + twoDgaussian: tuple = ("twoDgaussian", "generic") # noqa: N815 class AnalysisLogic(FitLogic): @@ -122,16 +125,17 @@

Module qudi_hira_analysis.analysis_logic

y: np.ndarray, fit_function: str, estimator: str, - parameters: list[Parameter] = None, - dims: str = "1d") -> Tuple[np.ndarray, np.ndarray, ModelResult]: - fit = {dims: {'default': {'fit_function': fit_function, 'estimator': estimator}}} + parameters: list[Parameter] | None = None, + dims: str = "1d") -> tuple[np.ndarray, np.ndarray, ModelResult]: + fit = { + dims: {'default': {'fit_function': fit_function, 'estimator': estimator}}} user_fit = self.validate_load_fits(fit) if parameters: user_fit[dims]["default"]["parameters"].add_many(*parameters) use_settings = {} - for key in user_fit[dims]["default"]["parameters"].keys(): + for key in user_fit[dims]["default"]["parameters"]: if parameters: if key in [p.name for p in parameters]: use_settings[key] = True @@ -153,14 +157,15 @@

Module qudi_hira_analysis.analysis_logic

y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, - parameters: list[Parameter] = None - ) -> Tuple[np.ndarray, np.ndarray, ModelResult]: + parameters: list[Parameter] | None = None + ) -> tuple[np.ndarray, np.ndarray, ModelResult]: """ Args: x: x data, can be string, numpy array or pandas Series y: y data, can be string, numpy array or pandas Series fit_function: fit function to use - data: pandas DataFrame containing x and y data, if None x and y must be numpy arrays or pandas Series + data: pandas DataFrame containing x and y data, if None x and y must be + numpy arrays or pandas Series parameters: list of parameters to use in fit (optional) Returns: @@ -172,7 +177,7 @@

Module qudi_hira_analysis.analysis_logic

dims: str = "1d" if data is None: - if isinstance(x, pd.Series) or isinstance(x, pd.Index): + if isinstance(x, (pd.Series, pd.Index)): x: np.ndarray = x.to_numpy() if isinstance(y, pd.Series): y: np.ndarray = y.to_numpy() @@ -191,7 +196,7 @@

Module qudi_hira_analysis.analysis_logic

dims=dims ) - def get_all_fits(self) -> Tuple[list, list]: + def get_all_fits(self) -> tuple[list, list]: """Get all available fits Returns: @@ -208,7 +213,7 @@

Module qudi_hira_analysis.analysis_logic

signal_start: float = 100e-9, signal_end: float = 300e-9, bin_width: float = 1e-9 - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray]: """ Calculate the mean of the signal window. @@ -259,7 +264,7 @@

Module qudi_hira_analysis.analysis_logic

signal_end: float = 300e-9, norm_start: float = 1000e-9, norm_end: float = 2000e-9, - bin_width: float = 1e-9) -> Tuple[np.ndarray, np.ndarray]: + bin_width: float = 1e-9) -> tuple[np.ndarray, np.ndarray]: """ Subtracts the mean of the signal window from the mean of the reference window. @@ -293,19 +298,20 @@

Module qudi_hira_analysis.analysis_logic

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 signal_data[ii] = signal_mean - reference_mean # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / abs(signal_sum) + 1 / abs(reference_sum)) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / abs(signal_sum) + 1 / abs(reference_sum)) return signal_data, error_data @@ -317,7 +323,7 @@

Module qudi_hira_analysis.analysis_logic

norm_start: float = 1000e-9, norm_end=2000e-9, bin_width: float = 1e-9 - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray]: """ Divides the mean of the signal window from the mean of the reference window. @@ -351,14 +357,14 @@

Module qudi_hira_analysis.analysis_logic

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 # Calculate normalized signal while avoiding division by zero if reference_mean > 0 and signal_mean >= 0: @@ -369,7 +375,8 @@

Module qudi_hira_analysis.analysis_logic

# Calculate measurement error while avoiding division by zero if reference_sum > 0 and signal_sum > 0: # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / signal_sum + 1 / reference_sum) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / signal_sum + 1 / reference_sum) else: error_data[ii] = 0.0 @@ -380,33 +387,42 @@

Module qudi_hira_analysis.analysis_logic

measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3, - ) -> Tuple[float, Tuple[float, float, float]]: + ) -> tuple[float, tuple[float, float, float]]: """ This method optimizes the hyperparameters of the ODMR analysis. It does so by randomly sampling a subset of the measurements and then optimizing the hyperparameters for them. Args: - measurements: A dictionary of measurements to optimize the hyperparameters for. + measurements: A dictionary of measurements to optimize the hyperparameters. num_params: The number of parameters to optimize. num_samples: The number of measurements to sample. Returns: The highest minimum R2 value and the optimized hyperparameters. """ - r2_threshs: np.ndarray = np.around(np.linspace(start=0.9, stop=0.99, num=num_params), decimals=2) - thresh_fracs: np.ndarray = np.around(np.linspace(start=0.5, stop=0.9, num=num_params), decimals=1) - sigma_thresh_fracs: np.ndarray = np.around(np.linspace(start=0.1, stop=0.2, num=num_params), decimals=1) + r2_threshs: np.ndarray = np.around( + np.linspace(start=0.9, stop=0.99, num=num_params), + decimals=2 + ) + thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.5, stop=0.9, num=num_params), + decimals=1 + ) + sigma_thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.1, stop=0.2, num=num_params), + decimals=1 + ) odmr_sample: dict = {} for k, v in random.sample(sorted(measurements.items()), k=num_samples): odmr_sample[k] = v highest_min_r2: float = 0 - optimal_params: Tuple[float, float, float] = (0, 0, 0) + optimal_params: tuple[float, float, float] = (0, 0, 0) - for idx, (r2_thresh, thresh_frac, sigma_thresh_frac) in enumerate( - product(r2_threshs, thresh_fracs, sigma_thresh_fracs)): + for r2_thresh, thresh_frac, sigma_thresh_frac in product( + r2_threshs, thresh_fracs, sigma_thresh_fracs): odmr_sample = self.fit_raster_odmr( odmr_sample, r2_thresh=r2_thresh, @@ -417,8 +433,8 @@

Module qudi_hira_analysis.analysis_logic

) r2s: np.ndarray = np.zeros(len(odmr_sample)) - for _idx, odmr in enumerate(odmr_sample.values()): - r2s[_idx] = odmr.fit_model.rsquared + for idx, odmr in enumerate(odmr_sample.values()): + r2s[idx] = odmr.fit_model.rsquared min_r2: float = np.min(r2s) if highest_min_r2 < min_r2: @@ -458,15 +474,18 @@

Module qudi_hira_analysis.analysis_logic

Args: odmr_measurements: Dict of ODMR data in MeasurementDataclasses - r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead of a single lorentzian + r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead + of a single lorentzian thresh_frac: Threshold fraction for the peak finding min_thresh: Minimum threshold for the peak finding sigma_thresh_frac: Change in threshold fraction for the peak finding - extract_pixel_from_filename: Extract `(row, col)` (in this format) from filename + extract_pixel_from_filename: Extract `(row, col)` (in this format) from + filename progress_bar: Show progress bar Returns: - Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes set + Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes + set """ model1, base_params1 = rof.make_lorentzian_model() @@ -478,19 +497,21 @@

Module qudi_hira_analysis.analysis_logic

x = odmr.data["Freq(MHz)"].to_numpy() y = odmr.data["Counts"].to_numpy() _, params1 = rof.estimate_lorentzian_dip(x, y, base_params1) - _, params2 = rof.estimate_lorentziandouble_dip(x, y, base_params2, thresh_frac, min_thresh, - sigma_thresh_frac) + _, params2 = rof.estimate_lorentziandouble_dip( + x, y, base_params2, thresh_frac, min_thresh, sigma_thresh_frac + ) args.append((x, y, model1, model2, params1, params2, r2_thresh)) # Parallel fitting model_results = Parallel(n_jobs=cpu_count())( delayed(self._lorentzian_fitting)( - x, y, model1, model2, params1, params2, r2_thresh) for x, y, model1, model2, params1, params2, r2_thresh + x, y, model1, model2, params1, params2, r2_thresh) for + x, y, model1, model2, params1, params2, r2_thresh in tqdm(args, disable=not progress_bar) ) - x = list(odmr_measurements.values())[0].data["Freq(MHz)"].to_numpy() + x = next(iter(odmr_measurements.values())).data["Freq(MHz)"].to_numpy() x_fit = np.linspace(start=x[0], stop=x[-1], num=int(len(x) * 2)) for odmr, res in zip(odmr_measurements.values(), model_results): @@ -504,11 +525,15 @@

Module qudi_hira_analysis.analysis_logic

# Plug results into the DataClass odmr.fit_model = res - odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, columns=["x_fit", "y_fit"]) + odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, + columns=["x_fit", "y_fit"]) if extract_pixel_from_filename: # Extract the pixel with regex from the filename - row, col = map(int, re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",")) + row, col = map( + int, + re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",") + ) odmr.xy_position = (row, col) return odmr_measurements @@ -572,16 +597,17 @@

Classes

y: np.ndarray, fit_function: str, estimator: str, - parameters: list[Parameter] = None, - dims: str = "1d") -> Tuple[np.ndarray, np.ndarray, ModelResult]: - fit = {dims: {'default': {'fit_function': fit_function, 'estimator': estimator}}} + parameters: list[Parameter] | None = None, + dims: str = "1d") -> tuple[np.ndarray, np.ndarray, ModelResult]: + fit = { + dims: {'default': {'fit_function': fit_function, 'estimator': estimator}}} user_fit = self.validate_load_fits(fit) if parameters: user_fit[dims]["default"]["parameters"].add_many(*parameters) use_settings = {} - for key in user_fit[dims]["default"]["parameters"].keys(): + for key in user_fit[dims]["default"]["parameters"]: if parameters: if key in [p.name for p in parameters]: use_settings[key] = True @@ -603,14 +629,15 @@

Classes

y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, - parameters: list[Parameter] = None - ) -> Tuple[np.ndarray, np.ndarray, ModelResult]: + parameters: list[Parameter] | None = None + ) -> tuple[np.ndarray, np.ndarray, ModelResult]: """ Args: x: x data, can be string, numpy array or pandas Series y: y data, can be string, numpy array or pandas Series fit_function: fit function to use - data: pandas DataFrame containing x and y data, if None x and y must be numpy arrays or pandas Series + data: pandas DataFrame containing x and y data, if None x and y must be + numpy arrays or pandas Series parameters: list of parameters to use in fit (optional) Returns: @@ -622,7 +649,7 @@

Classes

dims: str = "1d" if data is None: - if isinstance(x, pd.Series) or isinstance(x, pd.Index): + if isinstance(x, (pd.Series, pd.Index)): x: np.ndarray = x.to_numpy() if isinstance(y, pd.Series): y: np.ndarray = y.to_numpy() @@ -641,7 +668,7 @@

Classes

dims=dims ) - def get_all_fits(self) -> Tuple[list, list]: + def get_all_fits(self) -> tuple[list, list]: """Get all available fits Returns: @@ -658,7 +685,7 @@

Classes

signal_start: float = 100e-9, signal_end: float = 300e-9, bin_width: float = 1e-9 - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray]: """ Calculate the mean of the signal window. @@ -709,7 +736,7 @@

Classes

signal_end: float = 300e-9, norm_start: float = 1000e-9, norm_end: float = 2000e-9, - bin_width: float = 1e-9) -> Tuple[np.ndarray, np.ndarray]: + bin_width: float = 1e-9) -> tuple[np.ndarray, np.ndarray]: """ Subtracts the mean of the signal window from the mean of the reference window. @@ -743,19 +770,20 @@

Classes

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 signal_data[ii] = signal_mean - reference_mean # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / abs(signal_sum) + 1 / abs(reference_sum)) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / abs(signal_sum) + 1 / abs(reference_sum)) return signal_data, error_data @@ -767,7 +795,7 @@

Classes

norm_start: float = 1000e-9, norm_end=2000e-9, bin_width: float = 1e-9 - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray]: """ Divides the mean of the signal window from the mean of the reference window. @@ -801,14 +829,14 @@

Classes

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 # Calculate normalized signal while avoiding division by zero if reference_mean > 0 and signal_mean >= 0: @@ -819,7 +847,8 @@

Classes

# Calculate measurement error while avoiding division by zero if reference_sum > 0 and signal_sum > 0: # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / signal_sum + 1 / reference_sum) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / signal_sum + 1 / reference_sum) else: error_data[ii] = 0.0 @@ -830,33 +859,42 @@

Classes

measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3, - ) -> Tuple[float, Tuple[float, float, float]]: + ) -> tuple[float, tuple[float, float, float]]: """ This method optimizes the hyperparameters of the ODMR analysis. It does so by randomly sampling a subset of the measurements and then optimizing the hyperparameters for them. Args: - measurements: A dictionary of measurements to optimize the hyperparameters for. + measurements: A dictionary of measurements to optimize the hyperparameters. num_params: The number of parameters to optimize. num_samples: The number of measurements to sample. Returns: The highest minimum R2 value and the optimized hyperparameters. """ - r2_threshs: np.ndarray = np.around(np.linspace(start=0.9, stop=0.99, num=num_params), decimals=2) - thresh_fracs: np.ndarray = np.around(np.linspace(start=0.5, stop=0.9, num=num_params), decimals=1) - sigma_thresh_fracs: np.ndarray = np.around(np.linspace(start=0.1, stop=0.2, num=num_params), decimals=1) + r2_threshs: np.ndarray = np.around( + np.linspace(start=0.9, stop=0.99, num=num_params), + decimals=2 + ) + thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.5, stop=0.9, num=num_params), + decimals=1 + ) + sigma_thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.1, stop=0.2, num=num_params), + decimals=1 + ) odmr_sample: dict = {} for k, v in random.sample(sorted(measurements.items()), k=num_samples): odmr_sample[k] = v highest_min_r2: float = 0 - optimal_params: Tuple[float, float, float] = (0, 0, 0) + optimal_params: tuple[float, float, float] = (0, 0, 0) - for idx, (r2_thresh, thresh_frac, sigma_thresh_frac) in enumerate( - product(r2_threshs, thresh_fracs, sigma_thresh_fracs)): + for r2_thresh, thresh_frac, sigma_thresh_frac in product( + r2_threshs, thresh_fracs, sigma_thresh_fracs): odmr_sample = self.fit_raster_odmr( odmr_sample, r2_thresh=r2_thresh, @@ -867,8 +905,8 @@

Classes

) r2s: np.ndarray = np.zeros(len(odmr_sample)) - for _idx, odmr in enumerate(odmr_sample.values()): - r2s[_idx] = odmr.fit_model.rsquared + for idx, odmr in enumerate(odmr_sample.values()): + r2s[idx] = odmr.fit_model.rsquared min_r2: float = np.min(r2s) if highest_min_r2 < min_r2: @@ -908,15 +946,18 @@

Classes

Args: odmr_measurements: Dict of ODMR data in MeasurementDataclasses - r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead of a single lorentzian + r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead + of a single lorentzian thresh_frac: Threshold fraction for the peak finding min_thresh: Minimum threshold for the peak finding sigma_thresh_frac: Change in threshold fraction for the peak finding - extract_pixel_from_filename: Extract `(row, col)` (in this format) from filename + extract_pixel_from_filename: Extract `(row, col)` (in this format) from + filename progress_bar: Show progress bar Returns: - Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes set + Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes + set """ model1, base_params1 = rof.make_lorentzian_model() @@ -928,19 +969,21 @@

Classes

x = odmr.data["Freq(MHz)"].to_numpy() y = odmr.data["Counts"].to_numpy() _, params1 = rof.estimate_lorentzian_dip(x, y, base_params1) - _, params2 = rof.estimate_lorentziandouble_dip(x, y, base_params2, thresh_frac, min_thresh, - sigma_thresh_frac) + _, params2 = rof.estimate_lorentziandouble_dip( + x, y, base_params2, thresh_frac, min_thresh, sigma_thresh_frac + ) args.append((x, y, model1, model2, params1, params2, r2_thresh)) # Parallel fitting model_results = Parallel(n_jobs=cpu_count())( delayed(self._lorentzian_fitting)( - x, y, model1, model2, params1, params2, r2_thresh) for x, y, model1, model2, params1, params2, r2_thresh + x, y, model1, model2, params1, params2, r2_thresh) for + x, y, model1, model2, params1, params2, r2_thresh in tqdm(args, disable=not progress_bar) ) - x = list(odmr_measurements.values())[0].data["Freq(MHz)"].to_numpy() + x = next(iter(odmr_measurements.values())).data["Freq(MHz)"].to_numpy() x_fit = np.linspace(start=x[0], stop=x[-1], num=int(len(x) * 2)) for odmr, res in zip(odmr_measurements.values(), model_results): @@ -954,11 +997,15 @@

Classes

# Plug results into the DataClass odmr.fit_model = res - odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, columns=["x_fit", "y_fit"]) + odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, + columns=["x_fit", "y_fit"]) if extract_pixel_from_filename: # Extract the pixel with regex from the filename - row, col = map(int, re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",")) + row, col = map( + int, + re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",") + ) odmr.xy_position = (row, col) return odmr_measurements @@ -1003,7 +1050,8 @@

Class variables

Class for storing fit methods and estimators. Fit methods are stored as tuples of (method, estimator) -where method is the name of the fit method and estimator is the name of the estimator.

+where method is the name of the fit method and estimator is the name of the +estimator.

The fit functions available are:

@@ -1104,7 +1152,7 @@

Class variables

Static methods

-def analyze_mean(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, bin_width: float = 1e-09) ‑> Tuple[numpy.ndarray, numpy.ndarray] +def analyze_mean(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, bin_width: float = 1e-09) ‑> tuple[numpy.ndarray, numpy.ndarray]

Calculate the mean of the signal window.

@@ -1131,7 +1179,7 @@

Returns

signal_start: float = 100e-9, signal_end: float = 300e-9, bin_width: float = 1e-9 -) -> Tuple[np.ndarray, np.ndarray]: +) -> tuple[np.ndarray, np.ndarray]: """ Calculate the mean of the signal window. @@ -1177,7 +1225,7 @@

Returns

-def analyze_mean_norm(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, norm_start: float = 1e-06, norm_end=2e-06, bin_width: float = 1e-09) ‑> Tuple[numpy.ndarray, numpy.ndarray] +def analyze_mean_norm(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, norm_start: float = 1e-06, norm_end=2e-06, bin_width: float = 1e-09) ‑> tuple[numpy.ndarray, numpy.ndarray]

Divides the mean of the signal window from the mean of the reference window.

@@ -1210,7 +1258,7 @@

Returns

norm_start: float = 1000e-9, norm_end=2000e-9, bin_width: float = 1e-9 -) -> Tuple[np.ndarray, np.ndarray]: +) -> tuple[np.ndarray, np.ndarray]: """ Divides the mean of the signal window from the mean of the reference window. @@ -1244,14 +1292,14 @@

Returns

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 # Calculate normalized signal while avoiding division by zero if reference_mean > 0 and signal_mean >= 0: @@ -1262,7 +1310,8 @@

Returns

# Calculate measurement error while avoiding division by zero if reference_sum > 0 and signal_sum > 0: # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / signal_sum + 1 / reference_sum) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / signal_sum + 1 / reference_sum) else: error_data[ii] = 0.0 @@ -1270,7 +1319,7 @@

Returns

-def analyze_mean_reference(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, norm_start: float = 1e-06, norm_end: float = 2e-06, bin_width: float = 1e-09) ‑> Tuple[numpy.ndarray, numpy.ndarray] +def analyze_mean_reference(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, norm_start: float = 1e-06, norm_end: float = 2e-06, bin_width: float = 1e-09) ‑> tuple[numpy.ndarray, numpy.ndarray]

Subtracts the mean of the signal window from the mean of the reference window.

@@ -1302,7 +1351,7 @@

Returns

signal_end: float = 300e-9, norm_start: float = 1000e-9, norm_end: float = 2000e-9, - bin_width: float = 1e-9) -> Tuple[np.ndarray, np.ndarray]: + bin_width: float = 1e-9) -> tuple[np.ndarray, np.ndarray]: """ Subtracts the mean of the signal window from the mean of the reference window. @@ -1336,19 +1385,20 @@

Returns

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 signal_data[ii] = signal_mean - reference_mean # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / abs(signal_sum) + 1 / abs(reference_sum)) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / abs(signal_sum) + 1 / abs(reference_sum)) return signal_data, error_data @@ -1400,7 +1450,7 @@

Returns

Methods

-def fit(self, x: str | np.ndarray | pd.Series, y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, parameters: list[Parameter] = None) ‑> Tuple[np.ndarray, np.ndarray, ModelResult] +def fit(self, x: str | np.ndarray | pd.Series, y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, parameters: list[Parameter] | None = None) ‑> tuple[np.ndarray, np.ndarray, ModelResult]

Args

@@ -1412,7 +1462,8 @@

Methods

fit_function
fit function to use
data
-
pandas DataFrame containing x and y data, if None x and y must be numpy arrays or pandas Series
+
pandas DataFrame containing x and y data, if None x and y must be
+
numpy arrays or pandas Series
parameters
list of parameters to use in fit (optional)
@@ -1428,14 +1479,15 @@

Returns

y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, - parameters: list[Parameter] = None -) -> Tuple[np.ndarray, np.ndarray, ModelResult]: + parameters: list[Parameter] | None = None +) -> tuple[np.ndarray, np.ndarray, ModelResult]: """ Args: x: x data, can be string, numpy array or pandas Series y: y data, can be string, numpy array or pandas Series fit_function: fit function to use - data: pandas DataFrame containing x and y data, if None x and y must be numpy arrays or pandas Series + data: pandas DataFrame containing x and y data, if None x and y must be + numpy arrays or pandas Series parameters: list of parameters to use in fit (optional) Returns: @@ -1447,7 +1499,7 @@

Returns

dims: str = "1d" if data is None: - if isinstance(x, pd.Series) or isinstance(x, pd.Index): + if isinstance(x, (pd.Series, pd.Index)): x: np.ndarray = x.to_numpy() if isinstance(y, pd.Series): y: np.ndarray = y.to_numpy() @@ -1477,7 +1529,8 @@

Args

odmr_measurements
Dict of ODMR data in MeasurementDataclasses
r2_thresh
-
R^2 Threshold below which a double lorentzian is fitted instead of a single lorentzian
+
R^2 Threshold below which a double lorentzian is fitted instead +of a single lorentzian
thresh_frac
Threshold fraction for the peak finding
min_thresh
@@ -1485,12 +1538,14 @@

Args

sigma_thresh_frac
Change in threshold fraction for the peak finding
extract_pixel_from_filename
-
Extract (row, col) (in this format) from filename
+
Extract (row, col) (in this format) from +filename
progress_bar
Show progress bar

Returns

-

Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes set

+

Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes +set

Expand source code @@ -1510,15 +1565,18 @@

Returns

Args: odmr_measurements: Dict of ODMR data in MeasurementDataclasses - r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead of a single lorentzian + r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead + of a single lorentzian thresh_frac: Threshold fraction for the peak finding min_thresh: Minimum threshold for the peak finding sigma_thresh_frac: Change in threshold fraction for the peak finding - extract_pixel_from_filename: Extract `(row, col)` (in this format) from filename + extract_pixel_from_filename: Extract `(row, col)` (in this format) from + filename progress_bar: Show progress bar Returns: - Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes set + Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes + set """ model1, base_params1 = rof.make_lorentzian_model() @@ -1530,19 +1588,21 @@

Returns

x = odmr.data["Freq(MHz)"].to_numpy() y = odmr.data["Counts"].to_numpy() _, params1 = rof.estimate_lorentzian_dip(x, y, base_params1) - _, params2 = rof.estimate_lorentziandouble_dip(x, y, base_params2, thresh_frac, min_thresh, - sigma_thresh_frac) + _, params2 = rof.estimate_lorentziandouble_dip( + x, y, base_params2, thresh_frac, min_thresh, sigma_thresh_frac + ) args.append((x, y, model1, model2, params1, params2, r2_thresh)) # Parallel fitting model_results = Parallel(n_jobs=cpu_count())( delayed(self._lorentzian_fitting)( - x, y, model1, model2, params1, params2, r2_thresh) for x, y, model1, model2, params1, params2, r2_thresh + x, y, model1, model2, params1, params2, r2_thresh) for + x, y, model1, model2, params1, params2, r2_thresh in tqdm(args, disable=not progress_bar) ) - x = list(odmr_measurements.values())[0].data["Freq(MHz)"].to_numpy() + x = next(iter(odmr_measurements.values())).data["Freq(MHz)"].to_numpy() x_fit = np.linspace(start=x[0], stop=x[-1], num=int(len(x) * 2)) for odmr, res in zip(odmr_measurements.values(), model_results): @@ -1556,18 +1616,22 @@

Returns

# Plug results into the DataClass odmr.fit_model = res - odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, columns=["x_fit", "y_fit"]) + odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, + columns=["x_fit", "y_fit"]) if extract_pixel_from_filename: # Extract the pixel with regex from the filename - row, col = map(int, re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",")) + row, col = map( + int, + re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",") + ) odmr.xy_position = (row, col) return odmr_measurements
-def get_all_fits(self) ‑> Tuple[list, list] +def get_all_fits(self) ‑> tuple[list, list]

Get all available fits

@@ -1577,7 +1641,7 @@

Returns

Expand source code -
def get_all_fits(self) -> Tuple[list, list]:
+
def get_all_fits(self) -> tuple[list, list]:
     """Get all available fits
 
     Returns:
@@ -1590,7 +1654,7 @@ 

Returns

-def optimize_raster_odmr_params(self, measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3) ‑> Tuple[float, Tuple[float, float, float]] +def optimize_raster_odmr_params(self, measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3) ‑> tuple[float, tuple[float, float, float]]

This method optimizes the hyperparameters of the ODMR analysis. @@ -1599,7 +1663,7 @@

Returns

Args

measurements
-
A dictionary of measurements to optimize the hyperparameters for.
+
A dictionary of measurements to optimize the hyperparameters.
num_params
The number of parameters to optimize.
num_samples
@@ -1616,33 +1680,42 @@

Returns

measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3, -) -> Tuple[float, Tuple[float, float, float]]: +) -> tuple[float, tuple[float, float, float]]: """ This method optimizes the hyperparameters of the ODMR analysis. It does so by randomly sampling a subset of the measurements and then optimizing the hyperparameters for them. Args: - measurements: A dictionary of measurements to optimize the hyperparameters for. + measurements: A dictionary of measurements to optimize the hyperparameters. num_params: The number of parameters to optimize. num_samples: The number of measurements to sample. Returns: The highest minimum R2 value and the optimized hyperparameters. """ - r2_threshs: np.ndarray = np.around(np.linspace(start=0.9, stop=0.99, num=num_params), decimals=2) - thresh_fracs: np.ndarray = np.around(np.linspace(start=0.5, stop=0.9, num=num_params), decimals=1) - sigma_thresh_fracs: np.ndarray = np.around(np.linspace(start=0.1, stop=0.2, num=num_params), decimals=1) + r2_threshs: np.ndarray = np.around( + np.linspace(start=0.9, stop=0.99, num=num_params), + decimals=2 + ) + thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.5, stop=0.9, num=num_params), + decimals=1 + ) + sigma_thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.1, stop=0.2, num=num_params), + decimals=1 + ) odmr_sample: dict = {} for k, v in random.sample(sorted(measurements.items()), k=num_samples): odmr_sample[k] = v highest_min_r2: float = 0 - optimal_params: Tuple[float, float, float] = (0, 0, 0) + optimal_params: tuple[float, float, float] = (0, 0, 0) - for idx, (r2_thresh, thresh_frac, sigma_thresh_frac) in enumerate( - product(r2_threshs, thresh_fracs, sigma_thresh_fracs)): + for r2_thresh, thresh_frac, sigma_thresh_frac in product( + r2_threshs, thresh_fracs, sigma_thresh_fracs): odmr_sample = self.fit_raster_odmr( odmr_sample, r2_thresh=r2_thresh, @@ -1653,8 +1726,8 @@

Returns

) r2s: np.ndarray = np.zeros(len(odmr_sample)) - for _idx, odmr in enumerate(odmr_sample.values()): - r2s[_idx] = odmr.fit_model.rsquared + for idx, odmr in enumerate(odmr_sample.values()): + r2s[idx] = odmr.fit_model.rsquared min_r2: float = np.min(r2s) if highest_min_r2 < min_r2: @@ -1672,7 +1745,8 @@

Returns

Class for storing fit methods and estimators. Fit methods are stored as tuples of (method, estimator) -where method is the name of the fit method and estimator is the name of the estimator.

+where method is the name of the fit method and estimator is the name of the +estimator.

The fit functions available are:

@@ -1776,7 +1850,8 @@

Returns

""" Class for storing fit methods and estimators. Fit methods are stored as tuples of (method, estimator) - where method is the name of the fit method and estimator is the name of the estimator. + where method is the name of the fit method and estimator is the name of the + estimator. The fit functions available are: @@ -1827,7 +1902,7 @@

Returns

sinetriple: tuple = ("sinetriple", "generic") sinetriplewithexpdecay: tuple = ("sinetriplewithexpdecay", "generic") sinetriplewiththreeexpdecay: tuple = ("sinetriplewiththreeexpdecay", "generic") - twoDgaussian: tuple = ("twoDgaussian", "generic")
+ twoDgaussian: tuple = ("twoDgaussian", "generic") # noqa: N815

Class variables

diff --git a/docs/qudi_hira_analysis/data_handler.html b/docs/qudi_hira_analysis/data_handler.html index c543e02..ffbaade 100644 --- a/docs/qudi_hira_analysis/data_handler.html +++ b/docs/qudi_hira_analysis/data_handler.html @@ -31,20 +31,25 @@

Module qudi_hira_analysis.data_handler

import datetime import logging from pathlib import Path -from typing import List, TYPE_CHECKING, Callable - -import pySPM +from typing import TYPE_CHECKING, Callable from qudi_hira_analysis.analysis_logic import AnalysisLogic from qudi_hira_analysis.io_handler import IOHandler -from qudi_hira_analysis.measurement_dataclass import RawTimetrace, PulsedMeasurement, PulsedMeasurementDataclass, \ - LaserPulses, MeasurementDataclass +from qudi_hira_analysis.measurement_dataclass import ( + LaserPulses, + MeasurementDataclass, + PulsedMeasurement, + PulsedMeasurementDataclass, + RawTimetrace, +) if TYPE_CHECKING: - import pandas as pd import numpy as np + import pandas as pd + import pySPM -logging.basicConfig(format='%(name)s :: %(levelname)s :: %(message)s', level=logging.INFO) +logging.basicConfig(format='%(name)s :: %(levelname)s :: %(message)s', + level=logging.INFO) class DataLoader(IOHandler): @@ -57,24 +62,29 @@

Module qudi_hira_analysis.data_handler

super().__init__(**kwargs) # Create callables used in measurement dataclasses - self.default_qudi_loader: (Callable[[Path], pd.DataFrame], Callable[[Path], dict]) = ( + self.default_qudi_loader: ( + Callable[[Path], pd.DataFrame], Callable[[Path], dict]) = ( self.read_into_dataframe, self.read_qudi_parameters ) - self.confocal_qudi_loader: (Callable[[Path], np.ndarray], Callable[[Path], dict]) = ( + self.confocal_qudi_loader: ( + Callable[[Path], np.ndarray], Callable[[Path], dict]) = ( self.read_confocal_into_dataframe, self.read_qudi_parameters ) self.pixelscanner_qudi_loader: ( - Callable[[Path], (pySPM.SPM_image, pySPM.SPM_image)], Callable[[Path], dict]) = ( + Callable[[Path], (pySPM.SPM_image, pySPM.SPM_image)], + Callable[[Path], dict]) = ( self.read_pixelscanner_data, self.read_qudi_parameters ) - self.trace_qudi_loader: (Callable[[Path], np.ndarray], Callable[[Path], dict]) = ( + self.trace_qudi_loader: ( + Callable[[Path], np.ndarray], Callable[[Path], dict]) = ( self.read_into_ndarray_transposed, self.read_qudi_parameters ) - self.nanonis_loader: (Callable[[Path], pd.DataFrame], Callable[[Path], dict]) = ( + self.nanonis_loader: ( + Callable[[Path], pd.DataFrame], Callable[[Path], dict]) = ( self.read_nanonis_data, self.read_nanonis_parameters ) @@ -128,29 +138,33 @@

Module qudi_hira_analysis.data_handler

): self.log = logging.getLogger(__name__) - self.data_folder_path = self.__get_data_folder_path(data_folder, measurement_folder) + self.data_folder_path = self.__get_data_folder_path(data_folder, + measurement_folder) if copy_measurement_folder_structure: - self.figure_folder_path = self.__get_figure_folder_path(figure_folder, measurement_folder) + self.figure_folder_path = self.__get_figure_folder_path(figure_folder, + measurement_folder) else: - self.figure_folder_path = self.__get_figure_folder_path(figure_folder, Path()) + self.figure_folder_path = self.__get_figure_folder_path(figure_folder, + Path()) - super().__init__(base_read_path=self.data_folder_path, base_write_path=self.figure_folder_path) + super().__init__(base_read_path=self.data_folder_path, + base_write_path=self.figure_folder_path) self.timestamp_format_str = "%Y%m%d-%H%M-%S" def __get_data_folder_path(self, data_folder: Path, folder_name: Path) -> Path: - """ Check if folder exists, if not, create it and return absolute folder paths. """ + """ Check if folder exists, if not, create and return absolute folder paths. """ path = data_folder / folder_name if not path.exists(): - raise IOError("Data folder path does not exist.") + raise OSError("Data folder path does not exist.") self.log.info(f"Data folder path is {path}") return path def __get_figure_folder_path(self, figure_folder: Path, folder_name: Path) -> Path: - """ Check if folder exists, if not, create it and return absolute folder paths. """ + """ Check if folder exists, if not, create and return absolute folder paths. """ path = figure_folder / folder_name if not path.exists(): @@ -199,7 +213,7 @@

Module qudi_hira_analysis.data_handler

Print or return a string tree of the data folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. @@ -211,12 +225,13 @@

Module qudi_hira_analysis.data_handler

Print or return a string tree of the figure folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. """ - return self.__print_or_return_tree(self.figure_folder_path, print_tree=print_tree) + return self.__print_or_return_tree(self.figure_folder_path, + print_tree=print_tree) def _get_measurement_filepaths( self, @@ -228,10 +243,11 @@

Module qudi_hira_analysis.data_handler

List all measurement files for a single measurement type, regardless of date within a similar set (i.e. top level folder). """ - filepaths: List[Path] = [] + filepaths: list[Path] = [] for path in self.data_folder_path.rglob("*"): - if path.is_file() and measurement.lower() in str(path).lower(): + if path.is_file() and measurement.lower() in str( + path).lower(): if exclude_str is None or exclude_str not in str(path): if extension: if path.suffix == extension: @@ -252,7 +268,8 @@

Module qudi_hira_analysis.data_handler

timestamps = set() # Get set of unique timestamps containing pulsed_measurement_str - for filepath in self._get_measurement_filepaths(measurement=measurement_str, extension=extension, + for filepath in self._get_measurement_filepaths(measurement=measurement_str, + extension=extension, exclude_str="image_1.dat"): timestamps.add(filepath.name[:16]) filtered_filepaths.append(filepath) @@ -266,21 +283,28 @@

Module qudi_hira_analysis.data_handler

filename = filepath.name if filename.startswith(ts): if str(filename).endswith("laser_pulses.dat"): - lp = LaserPulses(filepath=filepath, loaders=self.trace_qudi_loader) + lp = LaserPulses(filepath=filepath, + loaders=self.trace_qudi_loader) elif str(filename).endswith("pulsed_measurement.dat"): - pm = PulsedMeasurement(filepath=filepath, loaders=self.default_qudi_loader) + pm = PulsedMeasurement(filepath=filepath, + loaders=self.default_qudi_loader) elif str(filename).endswith("raw_timetrace.dat"): - rt = RawTimetrace(filepath=filepath, loaders=self.trace_qudi_loader) + rt = RawTimetrace(filepath=filepath, + loaders=self.trace_qudi_loader) if lp and pm and rt: break if not (lp and pm and rt): - raise IOError(f"File '{filtered_filepaths[idx]}' is not a valid pulsed measurement.") + raise OSError( + f"'{filtered_filepaths[idx]}' is a invalid pulsed measurement.") pulsed_measurement_data[ts] = ( MeasurementDataclass( - timestamp=datetime.datetime.strptime(ts, self.timestamp_format_str), + timestamp=datetime.datetime.strptime( + ts, + self.timestamp_format_str + ), pulsed=PulsedMeasurementDataclass( measurement=pm, laser_pulses=lp, @@ -302,12 +326,16 @@

Module qudi_hira_analysis.data_handler

measurement_data: dict[str: MeasurementDataclass] = {} - for filepath in self._get_measurement_filepaths(measurement_str, extension, exclude_str): + for filepath in self._get_measurement_filepaths(measurement_str, extension, + exclude_str): ts = filepath.name[:16] measurement_data[ts] = ( MeasurementDataclass( filepath=filepath, - timestamp=datetime.datetime.strptime(ts, self.timestamp_format_str), + timestamp=datetime.datetime.strptime( + ts, + self.timestamp_format_str + ), _loaders=loaders ) ) @@ -345,9 +373,11 @@

Module qudi_hira_analysis.data_handler

loaders = self.default_qudi_loader exclude_str = None - for filepath in self._get_measurement_filepaths(measurement_str, extension, exclude_str): + for filepath in self._get_measurement_filepaths(measurement_str, extension, + exclude_str): timestamp = datetime.datetime.fromtimestamp(filepath.stat().st_mtime) - self.log.warning("Extracting timestamp from file modified time, may not be accurate.") + self.log.warning( + "Extracting timestamp from file modified time, may not be accurate.") ts = datetime.datetime.strftime(timestamp, self.timestamp_format_str) measurement_list[ts] = ( MeasurementDataclass( @@ -369,16 +399,18 @@

Module qudi_hira_analysis.data_handler

Lazy-load all measurements of a given type into a dictionary of dataclasses. Args: - measurement_str: The name of the measurement type to load e.g. t1, t2, confocal etc. - Recursively searches through the path defined by data_folder and measurement_folder. + measurement_str: The name of the measurement type to load e.g. t1, t2, + confocal etc. + Recursively searches through the path defined by + data_folder and measurement_folder. Case-insensitive (i.e. "odmr" == "ODMR" == "Odmr"). qudi: Whether the measurement is a qudi measurement (default: True). pulsed: Whether the measurement is a pulsed measurement (default: False). extension: The file extension of the measurement files (default: .dat). Returns: - dict: A dictionary where keys are the measurement timestamps and values are dataclasses containing the - measurement data. + dict: A dictionary where keys are the measurement timestamps and values are + dataclasses containing the measurement data. Examples: `dh` is an instance of the `DataHandler` class. @@ -402,9 +434,13 @@

Module qudi_hira_analysis.data_handler

measurement_str = measurement_str.lower() if qudi: - return self.__load_qudi_measurements_into_dataclass(measurement_str, pulsed=pulsed, extension=".dat") + return self.__load_qudi_measurements_into_dataclass( + measurement_str, pulsed=pulsed, extension=".dat" + ) else: - return self.__load_standard_measurements_into_dataclass(measurement_str, extension=extension) + return self.__load_standard_measurements_into_dataclass( + measurement_str, extension=extension + )
@@ -471,29 +507,33 @@

Examples

): self.log = logging.getLogger(__name__) - self.data_folder_path = self.__get_data_folder_path(data_folder, measurement_folder) + self.data_folder_path = self.__get_data_folder_path(data_folder, + measurement_folder) if copy_measurement_folder_structure: - self.figure_folder_path = self.__get_figure_folder_path(figure_folder, measurement_folder) + self.figure_folder_path = self.__get_figure_folder_path(figure_folder, + measurement_folder) else: - self.figure_folder_path = self.__get_figure_folder_path(figure_folder, Path()) + self.figure_folder_path = self.__get_figure_folder_path(figure_folder, + Path()) - super().__init__(base_read_path=self.data_folder_path, base_write_path=self.figure_folder_path) + super().__init__(base_read_path=self.data_folder_path, + base_write_path=self.figure_folder_path) self.timestamp_format_str = "%Y%m%d-%H%M-%S" def __get_data_folder_path(self, data_folder: Path, folder_name: Path) -> Path: - """ Check if folder exists, if not, create it and return absolute folder paths. """ + """ Check if folder exists, if not, create and return absolute folder paths. """ path = data_folder / folder_name if not path.exists(): - raise IOError("Data folder path does not exist.") + raise OSError("Data folder path does not exist.") self.log.info(f"Data folder path is {path}") return path def __get_figure_folder_path(self, figure_folder: Path, folder_name: Path) -> Path: - """ Check if folder exists, if not, create it and return absolute folder paths. """ + """ Check if folder exists, if not, create and return absolute folder paths. """ path = figure_folder / folder_name if not path.exists(): @@ -542,7 +582,7 @@

Examples

Print or return a string tree of the data folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. @@ -554,12 +594,13 @@

Examples

Print or return a string tree of the figure folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. """ - return self.__print_or_return_tree(self.figure_folder_path, print_tree=print_tree) + return self.__print_or_return_tree(self.figure_folder_path, + print_tree=print_tree) def _get_measurement_filepaths( self, @@ -571,10 +612,11 @@

Examples

List all measurement files for a single measurement type, regardless of date within a similar set (i.e. top level folder). """ - filepaths: List[Path] = [] + filepaths: list[Path] = [] for path in self.data_folder_path.rglob("*"): - if path.is_file() and measurement.lower() in str(path).lower(): + if path.is_file() and measurement.lower() in str( + path).lower(): if exclude_str is None or exclude_str not in str(path): if extension: if path.suffix == extension: @@ -595,7 +637,8 @@

Examples

timestamps = set() # Get set of unique timestamps containing pulsed_measurement_str - for filepath in self._get_measurement_filepaths(measurement=measurement_str, extension=extension, + for filepath in self._get_measurement_filepaths(measurement=measurement_str, + extension=extension, exclude_str="image_1.dat"): timestamps.add(filepath.name[:16]) filtered_filepaths.append(filepath) @@ -609,21 +652,28 @@

Examples

filename = filepath.name if filename.startswith(ts): if str(filename).endswith("laser_pulses.dat"): - lp = LaserPulses(filepath=filepath, loaders=self.trace_qudi_loader) + lp = LaserPulses(filepath=filepath, + loaders=self.trace_qudi_loader) elif str(filename).endswith("pulsed_measurement.dat"): - pm = PulsedMeasurement(filepath=filepath, loaders=self.default_qudi_loader) + pm = PulsedMeasurement(filepath=filepath, + loaders=self.default_qudi_loader) elif str(filename).endswith("raw_timetrace.dat"): - rt = RawTimetrace(filepath=filepath, loaders=self.trace_qudi_loader) + rt = RawTimetrace(filepath=filepath, + loaders=self.trace_qudi_loader) if lp and pm and rt: break if not (lp and pm and rt): - raise IOError(f"File '{filtered_filepaths[idx]}' is not a valid pulsed measurement.") + raise OSError( + f"'{filtered_filepaths[idx]}' is a invalid pulsed measurement.") pulsed_measurement_data[ts] = ( MeasurementDataclass( - timestamp=datetime.datetime.strptime(ts, self.timestamp_format_str), + timestamp=datetime.datetime.strptime( + ts, + self.timestamp_format_str + ), pulsed=PulsedMeasurementDataclass( measurement=pm, laser_pulses=lp, @@ -645,12 +695,16 @@

Examples

measurement_data: dict[str: MeasurementDataclass] = {} - for filepath in self._get_measurement_filepaths(measurement_str, extension, exclude_str): + for filepath in self._get_measurement_filepaths(measurement_str, extension, + exclude_str): ts = filepath.name[:16] measurement_data[ts] = ( MeasurementDataclass( filepath=filepath, - timestamp=datetime.datetime.strptime(ts, self.timestamp_format_str), + timestamp=datetime.datetime.strptime( + ts, + self.timestamp_format_str + ), _loaders=loaders ) ) @@ -688,9 +742,11 @@

Examples

loaders = self.default_qudi_loader exclude_str = None - for filepath in self._get_measurement_filepaths(measurement_str, extension, exclude_str): + for filepath in self._get_measurement_filepaths(measurement_str, extension, + exclude_str): timestamp = datetime.datetime.fromtimestamp(filepath.stat().st_mtime) - self.log.warning("Extracting timestamp from file modified time, may not be accurate.") + self.log.warning( + "Extracting timestamp from file modified time, may not be accurate.") ts = datetime.datetime.strftime(timestamp, self.timestamp_format_str) measurement_list[ts] = ( MeasurementDataclass( @@ -712,16 +768,18 @@

Examples

Lazy-load all measurements of a given type into a dictionary of dataclasses. Args: - measurement_str: The name of the measurement type to load e.g. t1, t2, confocal etc. - Recursively searches through the path defined by data_folder and measurement_folder. + measurement_str: The name of the measurement type to load e.g. t1, t2, + confocal etc. + Recursively searches through the path defined by + data_folder and measurement_folder. Case-insensitive (i.e. "odmr" == "ODMR" == "Odmr"). qudi: Whether the measurement is a qudi measurement (default: True). pulsed: Whether the measurement is a pulsed measurement (default: False). extension: The file extension of the measurement files (default: .dat). Returns: - dict: A dictionary where keys are the measurement timestamps and values are dataclasses containing the - measurement data. + dict: A dictionary where keys are the measurement timestamps and values are + dataclasses containing the measurement data. Examples: `dh` is an instance of the `DataHandler` class. @@ -745,9 +803,13 @@

Examples

measurement_str = measurement_str.lower() if qudi: - return self.__load_qudi_measurements_into_dataclass(measurement_str, pulsed=pulsed, extension=".dat") + return self.__load_qudi_measurements_into_dataclass( + measurement_str, pulsed=pulsed, extension=".dat" + ) else: - return self.__load_standard_measurements_into_dataclass(measurement_str, extension=extension) + return self.__load_standard_measurements_into_dataclass( + measurement_str, extension=extension + )

Ancestors

    @@ -766,7 +828,7 @@

    Methods

    Args

    print_tree
    -
    Whether to print the tree or return it as a string (default: True).
    +
    Print the tree or return it as a string (default: True).

    Returns

    @@ -782,7 +844,7 @@

    Returns

    Print or return a string tree of the data folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. @@ -798,7 +860,7 @@

    Returns

    Args

    print_tree
    -
    Whether to print the tree or return it as a string (default: True).
    +
    Print the tree or return it as a string (default: True).

    Returns

    @@ -814,12 +876,13 @@

    Returns

    Print or return a string tree of the figure folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. """ - return self.__print_or_return_tree(self.figure_folder_path, print_tree=print_tree) + return self.__print_or_return_tree(self.figure_folder_path, + print_tree=print_tree)
    @@ -830,8 +893,10 @@

    Returns

    Args

    measurement_str
    -
    The name of the measurement type to load e.g. t1, t2, confocal etc. -Recursively searches through the path defined by data_folder and measurement_folder. +
    The name of the measurement type to load e.g. t1, t2, +confocal etc. +Recursively searches through the path defined by +data_folder and measurement_folder. Case-insensitive (i.e. "odmr" == "ODMR" == "Odmr").
    qudi
    Whether the measurement is a qudi measurement (default: True).
    @@ -843,8 +908,8 @@

    Args

    Returns

    dict
    -
    A dictionary where keys are the measurement timestamps and values are dataclasses containing the -measurement data.
    +
    A dictionary where keys are the measurement timestamps and values are +dataclasses containing the measurement data.

    Examples

    dh is an instance of the DataHandler class.

    @@ -875,16 +940,18 @@

    Examples

    Lazy-load all measurements of a given type into a dictionary of dataclasses. Args: - measurement_str: The name of the measurement type to load e.g. t1, t2, confocal etc. - Recursively searches through the path defined by data_folder and measurement_folder. + measurement_str: The name of the measurement type to load e.g. t1, t2, + confocal etc. + Recursively searches through the path defined by + data_folder and measurement_folder. Case-insensitive (i.e. "odmr" == "ODMR" == "Odmr"). qudi: Whether the measurement is a qudi measurement (default: True). pulsed: Whether the measurement is a pulsed measurement (default: False). extension: The file extension of the measurement files (default: .dat). Returns: - dict: A dictionary where keys are the measurement timestamps and values are dataclasses containing the - measurement data. + dict: A dictionary where keys are the measurement timestamps and values are + dataclasses containing the measurement data. Examples: `dh` is an instance of the `DataHandler` class. @@ -908,9 +975,13 @@

    Examples

    measurement_str = measurement_str.lower() if qudi: - return self.__load_qudi_measurements_into_dataclass(measurement_str, pulsed=pulsed, extension=".dat") + return self.__load_qudi_measurements_into_dataclass( + measurement_str, pulsed=pulsed, extension=".dat" + ) else: - return self.__load_standard_measurements_into_dataclass(measurement_str, extension=extension)
    + return self.__load_standard_measurements_into_dataclass( + measurement_str, extension=extension + )
    @@ -977,24 +1048,29 @@

    Inherited members

    super().__init__(**kwargs) # Create callables used in measurement dataclasses - self.default_qudi_loader: (Callable[[Path], pd.DataFrame], Callable[[Path], dict]) = ( + self.default_qudi_loader: ( + Callable[[Path], pd.DataFrame], Callable[[Path], dict]) = ( self.read_into_dataframe, self.read_qudi_parameters ) - self.confocal_qudi_loader: (Callable[[Path], np.ndarray], Callable[[Path], dict]) = ( + self.confocal_qudi_loader: ( + Callable[[Path], np.ndarray], Callable[[Path], dict]) = ( self.read_confocal_into_dataframe, self.read_qudi_parameters ) self.pixelscanner_qudi_loader: ( - Callable[[Path], (pySPM.SPM_image, pySPM.SPM_image)], Callable[[Path], dict]) = ( + Callable[[Path], (pySPM.SPM_image, pySPM.SPM_image)], + Callable[[Path], dict]) = ( self.read_pixelscanner_data, self.read_qudi_parameters ) - self.trace_qudi_loader: (Callable[[Path], np.ndarray], Callable[[Path], dict]) = ( + self.trace_qudi_loader: ( + Callable[[Path], np.ndarray], Callable[[Path], dict]) = ( self.read_into_ndarray_transposed, self.read_qudi_parameters ) - self.nanonis_loader: (Callable[[Path], pd.DataFrame], Callable[[Path], dict]) = ( + self.nanonis_loader: ( + Callable[[Path], pd.DataFrame], Callable[[Path], dict]) = ( self.read_nanonis_data, self.read_nanonis_parameters ) diff --git a/docs/qudi_hira_analysis/helper_functions.html b/docs/qudi_hira_analysis/helper_functions.html index 4b2fe01..3783ff0 100644 --- a/docs/qudi_hira_analysis/helper_functions.html +++ b/docs/qudi_hira_analysis/helper_functions.html @@ -57,12 +57,14 @@

    Module qudi_hira_analysis.helper_functions

    count -= 1 if only_exp: - formatted_str = r"$10^{{ {} }}$".format(count) + formatted_str = fr"$10^{{ {count} }}$" else: if decimals == 0: - formatted_str = r"${{ {} }} {} 10^{{ {} }}$".format(int(number_to_format), separator, count) + formatted_str = r"${{ {} }} {} 10^{{ {} }}$".format( + int(number_to_format), separator, count) else: - formatted_str = r"${{ {} }} {} 10^{{ {} }}$".format(round(number_to_format, decimals), separator, count) + formatted_str = r"${{ {} }} {} 10^{{ {} }}$".format( + round(number_to_format, decimals), separator, count) return formatted_str @@ -72,19 +74,21 @@

    Module qudi_hira_analysis.helper_functions

    return rf"$10^{{{val:.0f}}}$" -def baseline_als(y: np.ndarray, lam: float = 1e6, p: float = 0.9, niter: int = 10) -> np.ndarray: +def baseline_als(y: np.ndarray, lam: float = 1e6, p: float = 0.9, + niter: int = 10) -> np.ndarray: """ Asymmetric least squares baseline. - Source: Paul H. C. Eilers, Hans F.M. Boelens. Baseline Correction with Asymmetric Least Squares Smoothing (2005). + Source: Paul H. C. Eilers, Hans F.M. Boelens. Baseline Correction with Asymmetric + Least Squares Smoothing (2005). """ - L = len(y) - D = sparse.csc_matrix(np.diff(np.eye(L), 2)) + L = len(y) # noqa: N806 + D = sparse.csc_matrix(np.diff(np.eye(L), 2)) # noqa: N806 w = np.ones(L) z = None - for i in range(niter): - W = sparse.spdiags(w, 0, L, L) - Z = W + lam * D.dot(D.transpose()) + for _ in range(niter): + W = sparse.spdiags(w, 0, L, L) # noqa: N806 + Z = W + lam * D.dot(D.transpose()) # noqa: N806 z = sparse.linalg.spsolve(Z, w * y) w = p * (y > z) + (1 - p) * (y < z) return z @@ -102,24 +106,27 @@

    Functions

    Asymmetric least squares baseline. -Source: Paul H. C. Eilers, Hans F.M. Boelens. Baseline Correction with Asymmetric Least Squares Smoothing (2005).

    +Source: Paul H. C. Eilers, Hans F.M. Boelens. Baseline Correction with Asymmetric +Least Squares Smoothing (2005).

    Expand source code -
    def baseline_als(y: np.ndarray, lam: float = 1e6, p: float = 0.9, niter: int = 10) -> np.ndarray:
    +
    def baseline_als(y: np.ndarray, lam: float = 1e6, p: float = 0.9,
    +                 niter: int = 10) -> np.ndarray:
         """
         Asymmetric least squares baseline.
    -    Source: Paul H. C. Eilers, Hans F.M. Boelens. Baseline Correction with Asymmetric Least Squares Smoothing (2005).
    +    Source: Paul H. C. Eilers, Hans F.M. Boelens. Baseline Correction with Asymmetric
    +    Least Squares Smoothing (2005).
         """
    -    L = len(y)
    -    D = sparse.csc_matrix(np.diff(np.eye(L), 2))
    +    L = len(y)  # noqa: N806
    +    D = sparse.csc_matrix(np.diff(np.eye(L), 2))  # noqa: N806
         w = np.ones(L)
     
         z = None
    -    for i in range(niter):
    -        W = sparse.spdiags(w, 0, L, L)
    -        Z = W + lam * D.dot(D.transpose())
    +    for _ in range(niter):
    +        W = sparse.spdiags(w, 0, L, L)  # noqa: N806
    +        Z = W + lam * D.dot(D.transpose())  # noqa: N806
             z = sparse.linalg.spsolve(Z, w * y)
             w = p * (y > z) + (1 - p) * (y < z)
         return z
    @@ -173,12 +180,14 @@

    Functions

    count -= 1 if only_exp: - formatted_str = r"$10^{{ {} }}$".format(count) + formatted_str = fr"$10^{{ {count} }}$" else: if decimals == 0: - formatted_str = r"${{ {} }} {} 10^{{ {} }}$".format(int(number_to_format), separator, count) + formatted_str = r"${{ {} }} {} 10^{{ {} }}$".format( + int(number_to_format), separator, count) else: - formatted_str = r"${{ {} }} {} 10^{{ {} }}$".format(round(number_to_format, decimals), separator, count) + formatted_str = r"${{ {} }} {} 10^{{ {} }}$".format( + round(number_to_format, decimals), separator, count) return formatted_str
    diff --git a/docs/qudi_hira_analysis/index.html b/docs/qudi_hira_analysis/index.html index d50bae2..72a1093 100644 --- a/docs/qudi_hira_analysis/index.html +++ b/docs/qudi_hira_analysis/index.html @@ -24,10 +24,11 @@

    Package qudi_hira_analysis

    Analytics suite for qubit SPM using FPGA timetaggers

    Getting started

    -

    Start by creating an instance of the DataHandler class. Specify the location you want to load data from -(data_folder), the location you want to save figures to (figure_folder) and (optionally) the -name of the measurement folder (measurement_folder). If a measurement folder is specified, its path will be combined -with the data folder path to form the full path to the measurement data.

    +

    Start by creating an instance of the DataHandler class. Specify the location you +want to load data from (data_folder), the location you want to save figures to ( +figure_folder) and (optionally) the name of the measurement folder ( +measurement_folder). If a measurement folder is specified, its path will be +combined with the data folder path to form the full path to the measurement data.

    from pathlib import Path
     import matplotlib.pyplot as plt
     import seaborn as sns
    @@ -44,10 +45,12 @@ 

    Getting started

    # qudi_hira_analysis.data_handler :: INFO :: Figure folder path is C:/QudiHiraAnalysis/20230101_NV1

    Loading data

    -

    To load a specific set of measurements from the data folder, use the DataHandler.load_measurements() method. -The method takes a string as an argument and searches for files with the string in the path. The files are lazy-loaded, -so the data is only loaded when it is needed. The method returns a dictionary, where the keys are the timestamps of the -measurements and the values are MeasurementDataclass objects.

    +

    To load a specific set of measurements from the data folder, use the +DataHandler.load_measurements() method. The method takes a string as an argument +and searches for files with the string in the path. The files are lazy-loaded, +so the data is only loaded when it is needed. The method returns a dictionary, +where the keys are the timestamps of the measurements and the values are +MeasurementDataclass objects.

    # Search and lazy-load all pulsed measurements with "odmr" in the path into Dataclasses
     odmr_measurements = dh.load_measurements("odmr", pulsed=True)
     odmr = odmr_measurements["20230101-0420-00"]
    @@ -65,8 +68,9 @@ 

    Loading data

    ... ... ...

    Fitting data

    -

    To fit data, call the AnalysisLogic.fit() method. This method accepts pandas DataFrames, numpy arrays or pandas Series -as inputs. To get the full list of available fit routines, explore the DataHandler.fit_function attribute or call +

    To fit data, call the AnalysisLogic.fit() method. This method accepts pandas +DataFrames, numpy arrays or pandas Series as inputs. To get the full list of +available fit routines, explore the DataHandler.fit_function attribute or call AnalysisLogic.get_all_fits().

    The fit functions available are:

@@ -207,9 +211,9 @@

Fitting data

Saving data

To save figures, call the IOHandler.save_figures() method. By default, -the figures are saved as JPG, PDF, PNG and SVG. -This can be changed by setting the only_jpg or only_pdf arguments to True. All other keyword arguments -are passed to the matplotlib.pyplot.savefig() function.

+the figures are saved as JPG, PDF, PNG and SVG. This can be changed by setting the +only_jpg or only_pdf arguments to True. All other keyword arguments are passed +to the matplotlib.pyplot.savefig() function.

# Save the figure to the figure folder specified earlier
 dh.save_figures(filepath=Path("odmr"), fig=ax.get_figure(),
                 only_pdf=True, bbox_inches="tight")
@@ -392,10 +396,11 @@ 

PYS data (pi3diamond compatibility)PYS data (pi3diamond compatibility)PYS data (pi3diamond compatibility)PYS data (pi3diamond compatibility)Classes

y: np.ndarray, fit_function: str, estimator: str, - parameters: list[Parameter] = None, - dims: str = "1d") -> Tuple[np.ndarray, np.ndarray, ModelResult]: - fit = {dims: {'default': {'fit_function': fit_function, 'estimator': estimator}}} + parameters: list[Parameter] | None = None, + dims: str = "1d") -> tuple[np.ndarray, np.ndarray, ModelResult]: + fit = { + dims: {'default': {'fit_function': fit_function, 'estimator': estimator}}} user_fit = self.validate_load_fits(fit) if parameters: user_fit[dims]["default"]["parameters"].add_many(*parameters) use_settings = {} - for key in user_fit[dims]["default"]["parameters"].keys(): + for key in user_fit[dims]["default"]["parameters"]: if parameters: if key in [p.name for p in parameters]: use_settings[key] = True @@ -827,14 +836,15 @@

Classes

y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, - parameters: list[Parameter] = None - ) -> Tuple[np.ndarray, np.ndarray, ModelResult]: + parameters: list[Parameter] | None = None + ) -> tuple[np.ndarray, np.ndarray, ModelResult]: """ Args: x: x data, can be string, numpy array or pandas Series y: y data, can be string, numpy array or pandas Series fit_function: fit function to use - data: pandas DataFrame containing x and y data, if None x and y must be numpy arrays or pandas Series + data: pandas DataFrame containing x and y data, if None x and y must be + numpy arrays or pandas Series parameters: list of parameters to use in fit (optional) Returns: @@ -846,7 +856,7 @@

Classes

dims: str = "1d" if data is None: - if isinstance(x, pd.Series) or isinstance(x, pd.Index): + if isinstance(x, (pd.Series, pd.Index)): x: np.ndarray = x.to_numpy() if isinstance(y, pd.Series): y: np.ndarray = y.to_numpy() @@ -865,7 +875,7 @@

Classes

dims=dims ) - def get_all_fits(self) -> Tuple[list, list]: + def get_all_fits(self) -> tuple[list, list]: """Get all available fits Returns: @@ -882,7 +892,7 @@

Classes

signal_start: float = 100e-9, signal_end: float = 300e-9, bin_width: float = 1e-9 - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray]: """ Calculate the mean of the signal window. @@ -933,7 +943,7 @@

Classes

signal_end: float = 300e-9, norm_start: float = 1000e-9, norm_end: float = 2000e-9, - bin_width: float = 1e-9) -> Tuple[np.ndarray, np.ndarray]: + bin_width: float = 1e-9) -> tuple[np.ndarray, np.ndarray]: """ Subtracts the mean of the signal window from the mean of the reference window. @@ -967,19 +977,20 @@

Classes

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 signal_data[ii] = signal_mean - reference_mean # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / abs(signal_sum) + 1 / abs(reference_sum)) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / abs(signal_sum) + 1 / abs(reference_sum)) return signal_data, error_data @@ -991,7 +1002,7 @@

Classes

norm_start: float = 1000e-9, norm_end=2000e-9, bin_width: float = 1e-9 - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray]: """ Divides the mean of the signal window from the mean of the reference window. @@ -1025,14 +1036,14 @@

Classes

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 # Calculate normalized signal while avoiding division by zero if reference_mean > 0 and signal_mean >= 0: @@ -1043,7 +1054,8 @@

Classes

# Calculate measurement error while avoiding division by zero if reference_sum > 0 and signal_sum > 0: # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / signal_sum + 1 / reference_sum) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / signal_sum + 1 / reference_sum) else: error_data[ii] = 0.0 @@ -1054,33 +1066,42 @@

Classes

measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3, - ) -> Tuple[float, Tuple[float, float, float]]: + ) -> tuple[float, tuple[float, float, float]]: """ This method optimizes the hyperparameters of the ODMR analysis. It does so by randomly sampling a subset of the measurements and then optimizing the hyperparameters for them. Args: - measurements: A dictionary of measurements to optimize the hyperparameters for. + measurements: A dictionary of measurements to optimize the hyperparameters. num_params: The number of parameters to optimize. num_samples: The number of measurements to sample. Returns: The highest minimum R2 value and the optimized hyperparameters. """ - r2_threshs: np.ndarray = np.around(np.linspace(start=0.9, stop=0.99, num=num_params), decimals=2) - thresh_fracs: np.ndarray = np.around(np.linspace(start=0.5, stop=0.9, num=num_params), decimals=1) - sigma_thresh_fracs: np.ndarray = np.around(np.linspace(start=0.1, stop=0.2, num=num_params), decimals=1) + r2_threshs: np.ndarray = np.around( + np.linspace(start=0.9, stop=0.99, num=num_params), + decimals=2 + ) + thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.5, stop=0.9, num=num_params), + decimals=1 + ) + sigma_thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.1, stop=0.2, num=num_params), + decimals=1 + ) odmr_sample: dict = {} for k, v in random.sample(sorted(measurements.items()), k=num_samples): odmr_sample[k] = v highest_min_r2: float = 0 - optimal_params: Tuple[float, float, float] = (0, 0, 0) + optimal_params: tuple[float, float, float] = (0, 0, 0) - for idx, (r2_thresh, thresh_frac, sigma_thresh_frac) in enumerate( - product(r2_threshs, thresh_fracs, sigma_thresh_fracs)): + for r2_thresh, thresh_frac, sigma_thresh_frac in product( + r2_threshs, thresh_fracs, sigma_thresh_fracs): odmr_sample = self.fit_raster_odmr( odmr_sample, r2_thresh=r2_thresh, @@ -1091,8 +1112,8 @@

Classes

) r2s: np.ndarray = np.zeros(len(odmr_sample)) - for _idx, odmr in enumerate(odmr_sample.values()): - r2s[_idx] = odmr.fit_model.rsquared + for idx, odmr in enumerate(odmr_sample.values()): + r2s[idx] = odmr.fit_model.rsquared min_r2: float = np.min(r2s) if highest_min_r2 < min_r2: @@ -1132,15 +1153,18 @@

Classes

Args: odmr_measurements: Dict of ODMR data in MeasurementDataclasses - r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead of a single lorentzian + r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead + of a single lorentzian thresh_frac: Threshold fraction for the peak finding min_thresh: Minimum threshold for the peak finding sigma_thresh_frac: Change in threshold fraction for the peak finding - extract_pixel_from_filename: Extract `(row, col)` (in this format) from filename + extract_pixel_from_filename: Extract `(row, col)` (in this format) from + filename progress_bar: Show progress bar Returns: - Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes set + Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes + set """ model1, base_params1 = rof.make_lorentzian_model() @@ -1152,19 +1176,21 @@

Classes

x = odmr.data["Freq(MHz)"].to_numpy() y = odmr.data["Counts"].to_numpy() _, params1 = rof.estimate_lorentzian_dip(x, y, base_params1) - _, params2 = rof.estimate_lorentziandouble_dip(x, y, base_params2, thresh_frac, min_thresh, - sigma_thresh_frac) + _, params2 = rof.estimate_lorentziandouble_dip( + x, y, base_params2, thresh_frac, min_thresh, sigma_thresh_frac + ) args.append((x, y, model1, model2, params1, params2, r2_thresh)) # Parallel fitting model_results = Parallel(n_jobs=cpu_count())( delayed(self._lorentzian_fitting)( - x, y, model1, model2, params1, params2, r2_thresh) for x, y, model1, model2, params1, params2, r2_thresh + x, y, model1, model2, params1, params2, r2_thresh) for + x, y, model1, model2, params1, params2, r2_thresh in tqdm(args, disable=not progress_bar) ) - x = list(odmr_measurements.values())[0].data["Freq(MHz)"].to_numpy() + x = next(iter(odmr_measurements.values())).data["Freq(MHz)"].to_numpy() x_fit = np.linspace(start=x[0], stop=x[-1], num=int(len(x) * 2)) for odmr, res in zip(odmr_measurements.values(), model_results): @@ -1178,11 +1204,15 @@

Classes

# Plug results into the DataClass odmr.fit_model = res - odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, columns=["x_fit", "y_fit"]) + odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, + columns=["x_fit", "y_fit"]) if extract_pixel_from_filename: # Extract the pixel with regex from the filename - row, col = map(int, re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",")) + row, col = map( + int, + re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",") + ) odmr.xy_position = (row, col) return odmr_measurements @@ -1227,7 +1257,8 @@

Class variables

Class for storing fit methods and estimators. Fit methods are stored as tuples of (method, estimator) -where method is the name of the fit method and estimator is the name of the estimator.

+where method is the name of the fit method and estimator is the name of the +estimator.

The fit functions available are:

@@ -1328,7 +1359,7 @@

Class variables

Static methods

-def analyze_mean(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, bin_width: float = 1e-09) ‑> Tuple[numpy.ndarray, numpy.ndarray] +def analyze_mean(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, bin_width: float = 1e-09) ‑> tuple[numpy.ndarray, numpy.ndarray]

Calculate the mean of the signal window.

@@ -1355,7 +1386,7 @@

Returns

signal_start: float = 100e-9, signal_end: float = 300e-9, bin_width: float = 1e-9 -) -> Tuple[np.ndarray, np.ndarray]: +) -> tuple[np.ndarray, np.ndarray]: """ Calculate the mean of the signal window. @@ -1401,7 +1432,7 @@

Returns

-def analyze_mean_norm(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, norm_start: float = 1e-06, norm_end=2e-06, bin_width: float = 1e-09) ‑> Tuple[numpy.ndarray, numpy.ndarray] +def analyze_mean_norm(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, norm_start: float = 1e-06, norm_end=2e-06, bin_width: float = 1e-09) ‑> tuple[numpy.ndarray, numpy.ndarray]

Divides the mean of the signal window from the mean of the reference window.

@@ -1434,7 +1465,7 @@

Returns

norm_start: float = 1000e-9, norm_end=2000e-9, bin_width: float = 1e-9 -) -> Tuple[np.ndarray, np.ndarray]: +) -> tuple[np.ndarray, np.ndarray]: """ Divides the mean of the signal window from the mean of the reference window. @@ -1468,14 +1499,14 @@

Returns

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 # Calculate normalized signal while avoiding division by zero if reference_mean > 0 and signal_mean >= 0: @@ -1486,7 +1517,8 @@

Returns

# Calculate measurement error while avoiding division by zero if reference_sum > 0 and signal_sum > 0: # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / signal_sum + 1 / reference_sum) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / signal_sum + 1 / reference_sum) else: error_data[ii] = 0.0 @@ -1494,7 +1526,7 @@

Returns

-def analyze_mean_reference(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, norm_start: float = 1e-06, norm_end: float = 2e-06, bin_width: float = 1e-09) ‑> Tuple[numpy.ndarray, numpy.ndarray] +def analyze_mean_reference(laser_data: np.ndarray, signal_start: float = 1e-07, signal_end: float = 3e-07, norm_start: float = 1e-06, norm_end: float = 2e-06, bin_width: float = 1e-09) ‑> tuple[numpy.ndarray, numpy.ndarray]

Subtracts the mean of the signal window from the mean of the reference window.

@@ -1526,7 +1558,7 @@

Returns

signal_end: float = 300e-9, norm_start: float = 1000e-9, norm_end: float = 2000e-9, - bin_width: float = 1e-9) -> Tuple[np.ndarray, np.ndarray]: + bin_width: float = 1e-9) -> tuple[np.ndarray, np.ndarray]: """ Subtracts the mean of the signal window from the mean of the reference window. @@ -1560,19 +1592,20 @@

Returns

# loop over all laser pulses and analyze them for ii, laser_arr in enumerate(laser_data): # calculate the sum and mean of the data in the normalization window - tmp_data = laser_arr[norm_start_bin:norm_end_bin] - reference_sum = np.sum(tmp_data) - reference_mean = (reference_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[norm_start_bin:norm_end_bin] + reference_sum = np.sum(counts) + reference_mean = (reference_sum / len(counts)) if len(counts) != 0 else 0.0 # calculate the sum and mean of the data in the signal window - tmp_data = laser_arr[signal_start_bin:signal_end_bin] - signal_sum = np.sum(tmp_data) - signal_mean = (signal_sum / len(tmp_data)) if len(tmp_data) != 0 else 0.0 + counts = laser_arr[signal_start_bin:signal_end_bin] + signal_sum = np.sum(counts) + signal_mean = (signal_sum / len(counts)) if len(counts) != 0 else 0.0 signal_data[ii] = signal_mean - reference_mean # calculate with respect to gaussian error 'evolution' - error_data[ii] = signal_data[ii] * np.sqrt(1 / abs(signal_sum) + 1 / abs(reference_sum)) + error_data[ii] = signal_data[ii] * np.sqrt( + 1 / abs(signal_sum) + 1 / abs(reference_sum)) return signal_data, error_data
@@ -1624,7 +1657,7 @@

Returns

Methods

-def fit(self, x: str | np.ndarray | pd.Series, y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, parameters: list[Parameter] = None) ‑> Tuple[np.ndarray, np.ndarray, ModelResult] +def fit(self, x: str | np.ndarray | pd.Series, y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, parameters: list[Parameter] | None = None) ‑> tuple[np.ndarray, np.ndarray, ModelResult]

Args

@@ -1636,7 +1669,8 @@

Methods

fit_function
fit function to use
data
-
pandas DataFrame containing x and y data, if None x and y must be numpy arrays or pandas Series
+
pandas DataFrame containing x and y data, if None x and y must be
+
numpy arrays or pandas Series
parameters
list of parameters to use in fit (optional)
@@ -1652,14 +1686,15 @@

Returns

y: str | np.ndarray | pd.Series, fit_function: FitMethodsAndEstimators, data: pd.DataFrame = None, - parameters: list[Parameter] = None -) -> Tuple[np.ndarray, np.ndarray, ModelResult]: + parameters: list[Parameter] | None = None +) -> tuple[np.ndarray, np.ndarray, ModelResult]: """ Args: x: x data, can be string, numpy array or pandas Series y: y data, can be string, numpy array or pandas Series fit_function: fit function to use - data: pandas DataFrame containing x and y data, if None x and y must be numpy arrays or pandas Series + data: pandas DataFrame containing x and y data, if None x and y must be + numpy arrays or pandas Series parameters: list of parameters to use in fit (optional) Returns: @@ -1671,7 +1706,7 @@

Returns

dims: str = "1d" if data is None: - if isinstance(x, pd.Series) or isinstance(x, pd.Index): + if isinstance(x, (pd.Series, pd.Index)): x: np.ndarray = x.to_numpy() if isinstance(y, pd.Series): y: np.ndarray = y.to_numpy() @@ -1701,7 +1736,8 @@

Args

odmr_measurements
Dict of ODMR data in MeasurementDataclasses
r2_thresh
-
R^2 Threshold below which a double lorentzian is fitted instead of a single lorentzian
+
R^2 Threshold below which a double lorentzian is fitted instead +of a single lorentzian
thresh_frac
Threshold fraction for the peak finding
min_thresh
@@ -1709,12 +1745,14 @@

Args

sigma_thresh_frac
Change in threshold fraction for the peak finding
extract_pixel_from_filename
-
Extract (row, col) (in this format) from filename
+
Extract (row, col) (in this format) from +filename
progress_bar
Show progress bar

Returns

-

Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes set

+

Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes +set

Expand source code @@ -1734,15 +1772,18 @@

Returns

Args: odmr_measurements: Dict of ODMR data in MeasurementDataclasses - r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead of a single lorentzian + r2_thresh: R^2 Threshold below which a double lorentzian is fitted instead + of a single lorentzian thresh_frac: Threshold fraction for the peak finding min_thresh: Minimum threshold for the peak finding sigma_thresh_frac: Change in threshold fraction for the peak finding - extract_pixel_from_filename: Extract `(row, col)` (in this format) from filename + extract_pixel_from_filename: Extract `(row, col)` (in this format) from + filename progress_bar: Show progress bar Returns: - Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes set + Dict of ODMR MeasurementDataclass with fit, fit model and pixels attributes + set """ model1, base_params1 = rof.make_lorentzian_model() @@ -1754,19 +1795,21 @@

Returns

x = odmr.data["Freq(MHz)"].to_numpy() y = odmr.data["Counts"].to_numpy() _, params1 = rof.estimate_lorentzian_dip(x, y, base_params1) - _, params2 = rof.estimate_lorentziandouble_dip(x, y, base_params2, thresh_frac, min_thresh, - sigma_thresh_frac) + _, params2 = rof.estimate_lorentziandouble_dip( + x, y, base_params2, thresh_frac, min_thresh, sigma_thresh_frac + ) args.append((x, y, model1, model2, params1, params2, r2_thresh)) # Parallel fitting model_results = Parallel(n_jobs=cpu_count())( delayed(self._lorentzian_fitting)( - x, y, model1, model2, params1, params2, r2_thresh) for x, y, model1, model2, params1, params2, r2_thresh + x, y, model1, model2, params1, params2, r2_thresh) for + x, y, model1, model2, params1, params2, r2_thresh in tqdm(args, disable=not progress_bar) ) - x = list(odmr_measurements.values())[0].data["Freq(MHz)"].to_numpy() + x = next(iter(odmr_measurements.values())).data["Freq(MHz)"].to_numpy() x_fit = np.linspace(start=x[0], stop=x[-1], num=int(len(x) * 2)) for odmr, res in zip(odmr_measurements.values(), model_results): @@ -1780,18 +1823,22 @@

Returns

# Plug results into the DataClass odmr.fit_model = res - odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, columns=["x_fit", "y_fit"]) + odmr.fit_data = pd.DataFrame(np.vstack((x_fit, y_fit)).T, + columns=["x_fit", "y_fit"]) if extract_pixel_from_filename: # Extract the pixel with regex from the filename - row, col = map(int, re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",")) + row, col = map( + int, + re.findall(r'(?<=\().*?(?=\))', odmr.filename)[0].split(",") + ) odmr.xy_position = (row, col) return odmr_measurements
-def get_all_fits(self) ‑> Tuple[list, list] +def get_all_fits(self) ‑> tuple[list, list]

Get all available fits

@@ -1801,7 +1848,7 @@

Returns

Expand source code -
def get_all_fits(self) -> Tuple[list, list]:
+
def get_all_fits(self) -> tuple[list, list]:
     """Get all available fits
 
     Returns:
@@ -1814,7 +1861,7 @@ 

Returns

-def optimize_raster_odmr_params(self, measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3) ‑> Tuple[float, Tuple[float, float, float]] +def optimize_raster_odmr_params(self, measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3) ‑> tuple[float, tuple[float, float, float]]

This method optimizes the hyperparameters of the ODMR analysis. @@ -1823,7 +1870,7 @@

Returns

Args

measurements
-
A dictionary of measurements to optimize the hyperparameters for.
+
A dictionary of measurements to optimize the hyperparameters.
num_params
The number of parameters to optimize.
num_samples
@@ -1840,33 +1887,42 @@

Returns

measurements: dict[str, MeasurementDataclass], num_samples: int = 10, num_params: int = 3, -) -> Tuple[float, Tuple[float, float, float]]: +) -> tuple[float, tuple[float, float, float]]: """ This method optimizes the hyperparameters of the ODMR analysis. It does so by randomly sampling a subset of the measurements and then optimizing the hyperparameters for them. Args: - measurements: A dictionary of measurements to optimize the hyperparameters for. + measurements: A dictionary of measurements to optimize the hyperparameters. num_params: The number of parameters to optimize. num_samples: The number of measurements to sample. Returns: The highest minimum R2 value and the optimized hyperparameters. """ - r2_threshs: np.ndarray = np.around(np.linspace(start=0.9, stop=0.99, num=num_params), decimals=2) - thresh_fracs: np.ndarray = np.around(np.linspace(start=0.5, stop=0.9, num=num_params), decimals=1) - sigma_thresh_fracs: np.ndarray = np.around(np.linspace(start=0.1, stop=0.2, num=num_params), decimals=1) + r2_threshs: np.ndarray = np.around( + np.linspace(start=0.9, stop=0.99, num=num_params), + decimals=2 + ) + thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.5, stop=0.9, num=num_params), + decimals=1 + ) + sigma_thresh_fracs: np.ndarray = np.around( + np.linspace(start=0.1, stop=0.2, num=num_params), + decimals=1 + ) odmr_sample: dict = {} for k, v in random.sample(sorted(measurements.items()), k=num_samples): odmr_sample[k] = v highest_min_r2: float = 0 - optimal_params: Tuple[float, float, float] = (0, 0, 0) + optimal_params: tuple[float, float, float] = (0, 0, 0) - for idx, (r2_thresh, thresh_frac, sigma_thresh_frac) in enumerate( - product(r2_threshs, thresh_fracs, sigma_thresh_fracs)): + for r2_thresh, thresh_frac, sigma_thresh_frac in product( + r2_threshs, thresh_fracs, sigma_thresh_fracs): odmr_sample = self.fit_raster_odmr( odmr_sample, r2_thresh=r2_thresh, @@ -1877,8 +1933,8 @@

Returns

) r2s: np.ndarray = np.zeros(len(odmr_sample)) - for _idx, odmr in enumerate(odmr_sample.values()): - r2s[_idx] = odmr.fit_model.rsquared + for idx, odmr in enumerate(odmr_sample.values()): + r2s[idx] = odmr.fit_model.rsquared min_r2: float = np.min(r2s) if highest_min_r2 < min_r2: @@ -1945,29 +2001,33 @@

Examples

): self.log = logging.getLogger(__name__) - self.data_folder_path = self.__get_data_folder_path(data_folder, measurement_folder) + self.data_folder_path = self.__get_data_folder_path(data_folder, + measurement_folder) if copy_measurement_folder_structure: - self.figure_folder_path = self.__get_figure_folder_path(figure_folder, measurement_folder) + self.figure_folder_path = self.__get_figure_folder_path(figure_folder, + measurement_folder) else: - self.figure_folder_path = self.__get_figure_folder_path(figure_folder, Path()) + self.figure_folder_path = self.__get_figure_folder_path(figure_folder, + Path()) - super().__init__(base_read_path=self.data_folder_path, base_write_path=self.figure_folder_path) + super().__init__(base_read_path=self.data_folder_path, + base_write_path=self.figure_folder_path) self.timestamp_format_str = "%Y%m%d-%H%M-%S" def __get_data_folder_path(self, data_folder: Path, folder_name: Path) -> Path: - """ Check if folder exists, if not, create it and return absolute folder paths. """ + """ Check if folder exists, if not, create and return absolute folder paths. """ path = data_folder / folder_name if not path.exists(): - raise IOError("Data folder path does not exist.") + raise OSError("Data folder path does not exist.") self.log.info(f"Data folder path is {path}") return path def __get_figure_folder_path(self, figure_folder: Path, folder_name: Path) -> Path: - """ Check if folder exists, if not, create it and return absolute folder paths. """ + """ Check if folder exists, if not, create and return absolute folder paths. """ path = figure_folder / folder_name if not path.exists(): @@ -2016,7 +2076,7 @@

Examples

Print or return a string tree of the data folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. @@ -2028,12 +2088,13 @@

Examples

Print or return a string tree of the figure folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. """ - return self.__print_or_return_tree(self.figure_folder_path, print_tree=print_tree) + return self.__print_or_return_tree(self.figure_folder_path, + print_tree=print_tree) def _get_measurement_filepaths( self, @@ -2045,10 +2106,11 @@

Examples

List all measurement files for a single measurement type, regardless of date within a similar set (i.e. top level folder). """ - filepaths: List[Path] = [] + filepaths: list[Path] = [] for path in self.data_folder_path.rglob("*"): - if path.is_file() and measurement.lower() in str(path).lower(): + if path.is_file() and measurement.lower() in str( + path).lower(): if exclude_str is None or exclude_str not in str(path): if extension: if path.suffix == extension: @@ -2069,7 +2131,8 @@

Examples

timestamps = set() # Get set of unique timestamps containing pulsed_measurement_str - for filepath in self._get_measurement_filepaths(measurement=measurement_str, extension=extension, + for filepath in self._get_measurement_filepaths(measurement=measurement_str, + extension=extension, exclude_str="image_1.dat"): timestamps.add(filepath.name[:16]) filtered_filepaths.append(filepath) @@ -2083,21 +2146,28 @@

Examples

filename = filepath.name if filename.startswith(ts): if str(filename).endswith("laser_pulses.dat"): - lp = LaserPulses(filepath=filepath, loaders=self.trace_qudi_loader) + lp = LaserPulses(filepath=filepath, + loaders=self.trace_qudi_loader) elif str(filename).endswith("pulsed_measurement.dat"): - pm = PulsedMeasurement(filepath=filepath, loaders=self.default_qudi_loader) + pm = PulsedMeasurement(filepath=filepath, + loaders=self.default_qudi_loader) elif str(filename).endswith("raw_timetrace.dat"): - rt = RawTimetrace(filepath=filepath, loaders=self.trace_qudi_loader) + rt = RawTimetrace(filepath=filepath, + loaders=self.trace_qudi_loader) if lp and pm and rt: break if not (lp and pm and rt): - raise IOError(f"File '{filtered_filepaths[idx]}' is not a valid pulsed measurement.") + raise OSError( + f"'{filtered_filepaths[idx]}' is a invalid pulsed measurement.") pulsed_measurement_data[ts] = ( MeasurementDataclass( - timestamp=datetime.datetime.strptime(ts, self.timestamp_format_str), + timestamp=datetime.datetime.strptime( + ts, + self.timestamp_format_str + ), pulsed=PulsedMeasurementDataclass( measurement=pm, laser_pulses=lp, @@ -2119,12 +2189,16 @@

Examples

measurement_data: dict[str: MeasurementDataclass] = {} - for filepath in self._get_measurement_filepaths(measurement_str, extension, exclude_str): + for filepath in self._get_measurement_filepaths(measurement_str, extension, + exclude_str): ts = filepath.name[:16] measurement_data[ts] = ( MeasurementDataclass( filepath=filepath, - timestamp=datetime.datetime.strptime(ts, self.timestamp_format_str), + timestamp=datetime.datetime.strptime( + ts, + self.timestamp_format_str + ), _loaders=loaders ) ) @@ -2162,9 +2236,11 @@

Examples

loaders = self.default_qudi_loader exclude_str = None - for filepath in self._get_measurement_filepaths(measurement_str, extension, exclude_str): + for filepath in self._get_measurement_filepaths(measurement_str, extension, + exclude_str): timestamp = datetime.datetime.fromtimestamp(filepath.stat().st_mtime) - self.log.warning("Extracting timestamp from file modified time, may not be accurate.") + self.log.warning( + "Extracting timestamp from file modified time, may not be accurate.") ts = datetime.datetime.strftime(timestamp, self.timestamp_format_str) measurement_list[ts] = ( MeasurementDataclass( @@ -2186,16 +2262,18 @@

Examples

Lazy-load all measurements of a given type into a dictionary of dataclasses. Args: - measurement_str: The name of the measurement type to load e.g. t1, t2, confocal etc. - Recursively searches through the path defined by data_folder and measurement_folder. + measurement_str: The name of the measurement type to load e.g. t1, t2, + confocal etc. + Recursively searches through the path defined by + data_folder and measurement_folder. Case-insensitive (i.e. "odmr" == "ODMR" == "Odmr"). qudi: Whether the measurement is a qudi measurement (default: True). pulsed: Whether the measurement is a pulsed measurement (default: False). extension: The file extension of the measurement files (default: .dat). Returns: - dict: A dictionary where keys are the measurement timestamps and values are dataclasses containing the - measurement data. + dict: A dictionary where keys are the measurement timestamps and values are + dataclasses containing the measurement data. Examples: `dh` is an instance of the `DataHandler` class. @@ -2219,9 +2297,13 @@

Examples

measurement_str = measurement_str.lower() if qudi: - return self.__load_qudi_measurements_into_dataclass(measurement_str, pulsed=pulsed, extension=".dat") + return self.__load_qudi_measurements_into_dataclass( + measurement_str, pulsed=pulsed, extension=".dat" + ) else: - return self.__load_standard_measurements_into_dataclass(measurement_str, extension=extension)
+ return self.__load_standard_measurements_into_dataclass( + measurement_str, extension=extension + )

Ancestors

    @@ -2240,7 +2322,7 @@

    Methods

    Args

    print_tree
    -
    Whether to print the tree or return it as a string (default: True).
    +
    Print the tree or return it as a string (default: True).

    Returns

    @@ -2256,7 +2338,7 @@

    Returns

    Print or return a string tree of the data folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. @@ -2272,7 +2354,7 @@

    Returns

    Args

    print_tree
    -
    Whether to print the tree or return it as a string (default: True).
    +
    Print the tree or return it as a string (default: True).

    Returns

    @@ -2288,12 +2370,13 @@

    Returns

    Print or return a string tree of the figure folder. Args: - print_tree: Whether to print the tree or return it as a string (default: True). + print_tree: Print the tree or return it as a string (default: True). Returns: str: The tree as a string if `print_tree is False. """ - return self.__print_or_return_tree(self.figure_folder_path, print_tree=print_tree) + return self.__print_or_return_tree(self.figure_folder_path, + print_tree=print_tree)
@@ -2304,8 +2387,10 @@

Returns

Args

measurement_str
-
The name of the measurement type to load e.g. t1, t2, confocal etc. -Recursively searches through the path defined by data_folder and measurement_folder. +
The name of the measurement type to load e.g. t1, t2, +confocal etc. +Recursively searches through the path defined by +data_folder and measurement_folder. Case-insensitive (i.e. "odmr" == "ODMR" == "Odmr").
qudi
Whether the measurement is a qudi measurement (default: True).
@@ -2317,8 +2402,8 @@

Args

Returns

dict
-
A dictionary where keys are the measurement timestamps and values are dataclasses containing the -measurement data.
+
A dictionary where keys are the measurement timestamps and values are +dataclasses containing the measurement data.

Examples

dh is an instance of the DataHandler class.

@@ -2349,16 +2434,18 @@

Examples

Lazy-load all measurements of a given type into a dictionary of dataclasses. Args: - measurement_str: The name of the measurement type to load e.g. t1, t2, confocal etc. - Recursively searches through the path defined by data_folder and measurement_folder. + measurement_str: The name of the measurement type to load e.g. t1, t2, + confocal etc. + Recursively searches through the path defined by + data_folder and measurement_folder. Case-insensitive (i.e. "odmr" == "ODMR" == "Odmr"). qudi: Whether the measurement is a qudi measurement (default: True). pulsed: Whether the measurement is a pulsed measurement (default: False). extension: The file extension of the measurement files (default: .dat). Returns: - dict: A dictionary where keys are the measurement timestamps and values are dataclasses containing the - measurement data. + dict: A dictionary where keys are the measurement timestamps and values are + dataclasses containing the measurement data. Examples: `dh` is an instance of the `DataHandler` class. @@ -2382,9 +2469,13 @@

Examples

measurement_str = measurement_str.lower() if qudi: - return self.__load_qudi_measurements_into_dataclass(measurement_str, pulsed=pulsed, extension=".dat") + return self.__load_qudi_measurements_into_dataclass( + measurement_str, pulsed=pulsed, extension=".dat" + ) else: - return self.__load_standard_measurements_into_dataclass(measurement_str, extension=extension)
+ return self.__load_standard_measurements_into_dataclass( + measurement_str, extension=extension + )
@@ -2436,7 +2527,8 @@

Inherited members

Class for storing fit methods and estimators. Fit methods are stored as tuples of (method, estimator) -where method is the name of the fit method and estimator is the name of the estimator.

+where method is the name of the fit method and estimator is the name of the +estimator.

The fit functions available are:

@@ -2540,7 +2632,8 @@

Inherited members

""" Class for storing fit methods and estimators. Fit methods are stored as tuples of (method, estimator) - where method is the name of the fit method and estimator is the name of the estimator. + where method is the name of the fit method and estimator is the name of the + estimator. The fit functions available are: @@ -2591,7 +2684,7 @@

Inherited members

sinetriple: tuple = ("sinetriple", "generic") sinetriplewithexpdecay: tuple = ("sinetriplewithexpdecay", "generic") sinetriplewiththreeexpdecay: tuple = ("sinetriplewiththreeexpdecay", "generic") - twoDgaussian: tuple = ("twoDgaussian", "generic") + twoDgaussian: tuple = ("twoDgaussian", "generic") # noqa: N815

Class variables

@@ -2687,7 +2780,7 @@

Class variables

class IOHandler -(base_read_path: pathlib.Path = None, base_write_path: pathlib.Path = None) +(base_read_path: Optional[pathlib.Path] = None, base_write_path: Optional[pathlib.Path] = None)

Handle all read and write operations.

@@ -2698,7 +2791,11 @@

Class variables

class IOHandler:
     """ Handle all read and write operations. """
 
-    def __init__(self, base_read_path: Path = None, base_write_path: Path = None):
+    def __init__(
+            self,
+            base_read_path: Optional[Path] = None,
+            base_write_path: Optional[Path] = None
+    ):
         super().__init__()
         self.base_read_path = base_read_path
         self.base_write_path = base_write_path
@@ -2764,7 +2861,9 @@ 

Class variables

elif filepath.suffix == "": return func(self, filepath.with_suffix(ext), **kwargs) else: - raise IOError(f"Invalid extension '{filepath.suffix}' in '{filepath}', extension should be '{ext}'") + raise OSError( + f"Invalid extension '{filepath.suffix}' in '{filepath}', " + f"extension should be '{ext}'") return wrapper @@ -2795,13 +2894,16 @@

Class variables

# Add params to dictionary label, value = line.split(":") if value != "\n": - params[label] = ast.literal_eval(inspect.cleandoc(value)) + params[label] = ast.literal_eval( + inspect.cleandoc(value)) elif line.count(":") == 3: # Handle files with timestamps in them label = line.split(":")[0] timestamp_str = "".join(line.split(":")[1:]).strip() - datetime_str = datetime.datetime.strptime(timestamp_str, "%d.%m.%Y %Hh%Mmin%Ss").replace( - tzinfo=datetime.timezone.utc) + datetime_str = datetime.datetime.strptime( + timestamp_str, + "%d.%m.%Y %Hh%Mmin%Ss" + ).replace(tzinfo=datetime.timezone.utc) params[label] = datetime_str except Exception as _: pass @@ -2820,7 +2922,8 @@

Class variables

""" with open(filepath) as handle: # Generate column names for DataFrame by parsing the file - *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), handle) + *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), + handle) names = names[1:].strip().split("\t") return pd.read_csv(filepath, names=names, comment="#", sep="\t") @@ -2840,7 +2943,7 @@

Class variables

""" Read a qudi confocal data file into a pandas DataFrame for analysis. """ confocal_params = self.read_qudi_parameters(filepath) data = self.read_into_ndarray(filepath, delimiter="\t") - # Use the confocal parameters to generate the index and columns for the DataFrame + # Use the confocal parameters to generate the index & columns for the DataFrame index = np.linspace( confocal_params['X image min (m)'], confocal_params['X image max (m)'], @@ -2872,7 +2975,7 @@

Class variables

""" Read raw .pys data files into a dictionary. """ byte_dict = np.load(str(filepath), encoding="bytes", allow_pickle=True) # Convert byte string keys to normal strings - return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict.keys()} + return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict} @_add_base_read_path @_check_extension(".pkl") @@ -2928,11 +3031,8 @@

Class variables

pass else: label, value, _ = line.split("\t") - try: - # Convert strings to number where possible + with contextlib.suppress(ValueError): value = float(value) - except ValueError: - pass if "Oscillation Control>" in label: label = label.replace("Oscillation Control>", "") parameters[label] = value @@ -2998,7 +3098,9 @@

Class variables

DataFrame containing the data. """ # Extract only the origin timestamp - origin = pd.read_excel(filepath, skiprows=1, nrows=1, usecols=[1], header=None)[1][0] + origin = pd.read_excel( + filepath, skiprows=1, nrows=1, usecols=[1], header=None + )[1][0] # Remove any tzinfo to prevent future exceptions in pandas origin = origin.replace("CET", "") # Parse datetime object from timestamp @@ -3024,7 +3126,8 @@

Class variables

Returns: DataFrame containing the wavelength and intensity data. """ - df = pd.read_csv(filepath, sep="\t", skiprows=14, names=["wavelength", "intensity"]) + df = pd.read_csv(filepath, sep="\t", skiprows=14, + names=["wavelength", "intensity"]) return df @staticmethod @@ -3037,7 +3140,8 @@

Class variables

backward_counts = np.flip(np.stack(split_array[1::2]), axis=1) return forward_counts, backward_counts - def read_pixelscanner_data(self, filepath: Path) -> (pySPM.SPM_image, pySPM.SPM_image): + def read_pixelscanner_data(self, filepath: Path) -> ( + pySPM.SPM_image, pySPM.SPM_image): """ Read data from a PixelScanner measurement. Args: @@ -3056,7 +3160,8 @@

Class variables

fwd, bwd = self.__get_forward_backward_counts(df["count_rates"], num_pixels) except KeyError: try: - fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], num_pixels) + fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], + num_pixels) except KeyError: # Support old data format fwd = df["forward (cps)"].to_numpy().reshape(num_pixels, num_pixels) @@ -3175,7 +3280,7 @@

Returns

""" Read a qudi confocal data file into a pandas DataFrame for analysis. """ confocal_params = self.read_qudi_parameters(filepath) data = self.read_into_ndarray(filepath, delimiter="\t") - # Use the confocal parameters to generate the index and columns for the DataFrame + # Use the confocal parameters to generate the index & columns for the DataFrame index = np.linspace( confocal_params['X image min (m)'], confocal_params['X image max (m)'], @@ -3251,7 +3356,8 @@

Returns

""" with open(filepath) as handle: # Generate column names for DataFrame by parsing the file - *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), handle) + *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), + handle) names = names[1:].strip().split("\t") return pd.read_csv(filepath, names=names, comment="#", sep="\t")
@@ -3314,7 +3420,9 @@

Returns

DataFrame containing the data. """ # Extract only the origin timestamp - origin = pd.read_excel(filepath, skiprows=1, nrows=1, usecols=[1], header=None)[1][0] + origin = pd.read_excel( + filepath, skiprows=1, nrows=1, usecols=[1], header=None + )[1][0] # Remove any tzinfo to prevent future exceptions in pandas origin = origin.replace("CET", "") # Parse datetime object from timestamp @@ -3409,11 +3517,8 @@

Returns

pass else: label, value, _ = line.split("\t") - try: - # Convert strings to number where possible + with contextlib.suppress(ValueError): value = float(value) - except ValueError: - pass if "Oscillation Control>" in label: label = label.replace("Oscillation Control>", "") parameters[label] = value @@ -3477,7 +3582,8 @@

Returns

Returns: DataFrame containing the wavelength and intensity data. """ - df = pd.read_csv(filepath, sep="\t", skiprows=14, names=["wavelength", "intensity"]) + df = pd.read_csv(filepath, sep="\t", skiprows=14, + names=["wavelength", "intensity"]) return df
@@ -3536,7 +3642,8 @@

Returns

Expand source code -
def read_pixelscanner_data(self, filepath: Path) -> (pySPM.SPM_image, pySPM.SPM_image):
+
def read_pixelscanner_data(self, filepath: Path) -> (
+        pySPM.SPM_image, pySPM.SPM_image):
     """ Read data from a PixelScanner measurement.
 
     Args:
@@ -3555,7 +3662,8 @@ 

Returns

fwd, bwd = self.__get_forward_backward_counts(df["count_rates"], num_pixels) except KeyError: try: - fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], num_pixels) + fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], + num_pixels) except KeyError: # Support old data format fwd = df["forward (cps)"].to_numpy().reshape(num_pixels, num_pixels) @@ -3599,7 +3707,7 @@

Returns

""" Read raw .pys data files into a dictionary. """ byte_dict = np.load(str(filepath), encoding="bytes", allow_pickle=True) # Convert byte string keys to normal strings - return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict.keys()}
+ return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict}
@@ -3643,13 +3751,16 @@

Returns

# Add params to dictionary label, value = line.split(":") if value != "\n": - params[label] = ast.literal_eval(inspect.cleandoc(value)) + params[label] = ast.literal_eval( + inspect.cleandoc(value)) elif line.count(":") == 3: # Handle files with timestamps in them label = line.split(":")[0] timestamp_str = "".join(line.split(":")[1:]).strip() - datetime_str = datetime.datetime.strptime(timestamp_str, "%d.%m.%Y %Hh%Mmin%Ss").replace( - tzinfo=datetime.timezone.utc) + datetime_str = datetime.datetime.strptime( + timestamp_str, + "%d.%m.%Y %Hh%Mmin%Ss" + ).replace(tzinfo=datetime.timezone.utc) params[label] = datetime_str except Exception as _: pass diff --git a/docs/qudi_hira_analysis/io_handler.html b/docs/qudi_hira_analysis/io_handler.html index 2beee87..eef932c 100644 --- a/docs/qudi_hira_analysis/io_handler.html +++ b/docs/qudi_hira_analysis/io_handler.html @@ -27,13 +27,14 @@

Module qudi_hira_analysis.io_handler

Expand source code
import ast
+import contextlib
 import datetime
 import inspect
 import itertools
 import pickle
 from functools import wraps
 from pathlib import Path
-from typing import Callable
+from typing import Callable, Optional
 
 import matplotlib.pyplot as plt
 import numpy as np
@@ -44,7 +45,11 @@ 

Module qudi_hira_analysis.io_handler

class IOHandler: """ Handle all read and write operations. """ - def __init__(self, base_read_path: Path = None, base_write_path: Path = None): + def __init__( + self, + base_read_path: Optional[Path] = None, + base_write_path: Optional[Path] = None + ): super().__init__() self.base_read_path = base_read_path self.base_write_path = base_write_path @@ -110,7 +115,9 @@

Module qudi_hira_analysis.io_handler

elif filepath.suffix == "": return func(self, filepath.with_suffix(ext), **kwargs) else: - raise IOError(f"Invalid extension '{filepath.suffix}' in '{filepath}', extension should be '{ext}'") + raise OSError( + f"Invalid extension '{filepath.suffix}' in '{filepath}', " + f"extension should be '{ext}'") return wrapper @@ -141,13 +148,16 @@

Module qudi_hira_analysis.io_handler

# Add params to dictionary label, value = line.split(":") if value != "\n": - params[label] = ast.literal_eval(inspect.cleandoc(value)) + params[label] = ast.literal_eval( + inspect.cleandoc(value)) elif line.count(":") == 3: # Handle files with timestamps in them label = line.split(":")[0] timestamp_str = "".join(line.split(":")[1:]).strip() - datetime_str = datetime.datetime.strptime(timestamp_str, "%d.%m.%Y %Hh%Mmin%Ss").replace( - tzinfo=datetime.timezone.utc) + datetime_str = datetime.datetime.strptime( + timestamp_str, + "%d.%m.%Y %Hh%Mmin%Ss" + ).replace(tzinfo=datetime.timezone.utc) params[label] = datetime_str except Exception as _: pass @@ -166,7 +176,8 @@

Module qudi_hira_analysis.io_handler

""" with open(filepath) as handle: # Generate column names for DataFrame by parsing the file - *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), handle) + *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), + handle) names = names[1:].strip().split("\t") return pd.read_csv(filepath, names=names, comment="#", sep="\t") @@ -186,7 +197,7 @@

Module qudi_hira_analysis.io_handler

""" Read a qudi confocal data file into a pandas DataFrame for analysis. """ confocal_params = self.read_qudi_parameters(filepath) data = self.read_into_ndarray(filepath, delimiter="\t") - # Use the confocal parameters to generate the index and columns for the DataFrame + # Use the confocal parameters to generate the index & columns for the DataFrame index = np.linspace( confocal_params['X image min (m)'], confocal_params['X image max (m)'], @@ -218,7 +229,7 @@

Module qudi_hira_analysis.io_handler

""" Read raw .pys data files into a dictionary. """ byte_dict = np.load(str(filepath), encoding="bytes", allow_pickle=True) # Convert byte string keys to normal strings - return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict.keys()} + return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict} @_add_base_read_path @_check_extension(".pkl") @@ -274,11 +285,8 @@

Module qudi_hira_analysis.io_handler

pass else: label, value, _ = line.split("\t") - try: - # Convert strings to number where possible + with contextlib.suppress(ValueError): value = float(value) - except ValueError: - pass if "Oscillation Control>" in label: label = label.replace("Oscillation Control>", "") parameters[label] = value @@ -344,7 +352,9 @@

Module qudi_hira_analysis.io_handler

DataFrame containing the data. """ # Extract only the origin timestamp - origin = pd.read_excel(filepath, skiprows=1, nrows=1, usecols=[1], header=None)[1][0] + origin = pd.read_excel( + filepath, skiprows=1, nrows=1, usecols=[1], header=None + )[1][0] # Remove any tzinfo to prevent future exceptions in pandas origin = origin.replace("CET", "") # Parse datetime object from timestamp @@ -370,7 +380,8 @@

Module qudi_hira_analysis.io_handler

Returns: DataFrame containing the wavelength and intensity data. """ - df = pd.read_csv(filepath, sep="\t", skiprows=14, names=["wavelength", "intensity"]) + df = pd.read_csv(filepath, sep="\t", skiprows=14, + names=["wavelength", "intensity"]) return df @staticmethod @@ -383,7 +394,8 @@

Module qudi_hira_analysis.io_handler

backward_counts = np.flip(np.stack(split_array[1::2]), axis=1) return forward_counts, backward_counts - def read_pixelscanner_data(self, filepath: Path) -> (pySPM.SPM_image, pySPM.SPM_image): + def read_pixelscanner_data(self, filepath: Path) -> ( + pySPM.SPM_image, pySPM.SPM_image): """ Read data from a PixelScanner measurement. Args: @@ -402,7 +414,8 @@

Module qudi_hira_analysis.io_handler

fwd, bwd = self.__get_forward_backward_counts(df["count_rates"], num_pixels) except KeyError: try: - fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], num_pixels) + fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], + num_pixels) except KeyError: # Support old data format fwd = df["forward (cps)"].to_numpy().reshape(num_pixels, num_pixels) @@ -482,7 +495,7 @@

Classes

class IOHandler -(base_read_path: pathlib.Path = None, base_write_path: pathlib.Path = None) +(base_read_path: Optional[pathlib.Path] = None, base_write_path: Optional[pathlib.Path] = None)

Handle all read and write operations.

@@ -493,7 +506,11 @@

Classes

class IOHandler:
     """ Handle all read and write operations. """
 
-    def __init__(self, base_read_path: Path = None, base_write_path: Path = None):
+    def __init__(
+            self,
+            base_read_path: Optional[Path] = None,
+            base_write_path: Optional[Path] = None
+    ):
         super().__init__()
         self.base_read_path = base_read_path
         self.base_write_path = base_write_path
@@ -559,7 +576,9 @@ 

Classes

elif filepath.suffix == "": return func(self, filepath.with_suffix(ext), **kwargs) else: - raise IOError(f"Invalid extension '{filepath.suffix}' in '{filepath}', extension should be '{ext}'") + raise OSError( + f"Invalid extension '{filepath.suffix}' in '{filepath}', " + f"extension should be '{ext}'") return wrapper @@ -590,13 +609,16 @@

Classes

# Add params to dictionary label, value = line.split(":") if value != "\n": - params[label] = ast.literal_eval(inspect.cleandoc(value)) + params[label] = ast.literal_eval( + inspect.cleandoc(value)) elif line.count(":") == 3: # Handle files with timestamps in them label = line.split(":")[0] timestamp_str = "".join(line.split(":")[1:]).strip() - datetime_str = datetime.datetime.strptime(timestamp_str, "%d.%m.%Y %Hh%Mmin%Ss").replace( - tzinfo=datetime.timezone.utc) + datetime_str = datetime.datetime.strptime( + timestamp_str, + "%d.%m.%Y %Hh%Mmin%Ss" + ).replace(tzinfo=datetime.timezone.utc) params[label] = datetime_str except Exception as _: pass @@ -615,7 +637,8 @@

Classes

""" with open(filepath) as handle: # Generate column names for DataFrame by parsing the file - *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), handle) + *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), + handle) names = names[1:].strip().split("\t") return pd.read_csv(filepath, names=names, comment="#", sep="\t") @@ -635,7 +658,7 @@

Classes

""" Read a qudi confocal data file into a pandas DataFrame for analysis. """ confocal_params = self.read_qudi_parameters(filepath) data = self.read_into_ndarray(filepath, delimiter="\t") - # Use the confocal parameters to generate the index and columns for the DataFrame + # Use the confocal parameters to generate the index & columns for the DataFrame index = np.linspace( confocal_params['X image min (m)'], confocal_params['X image max (m)'], @@ -667,7 +690,7 @@

Classes

""" Read raw .pys data files into a dictionary. """ byte_dict = np.load(str(filepath), encoding="bytes", allow_pickle=True) # Convert byte string keys to normal strings - return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict.keys()} + return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict} @_add_base_read_path @_check_extension(".pkl") @@ -723,11 +746,8 @@

Classes

pass else: label, value, _ = line.split("\t") - try: - # Convert strings to number where possible + with contextlib.suppress(ValueError): value = float(value) - except ValueError: - pass if "Oscillation Control>" in label: label = label.replace("Oscillation Control>", "") parameters[label] = value @@ -793,7 +813,9 @@

Classes

DataFrame containing the data. """ # Extract only the origin timestamp - origin = pd.read_excel(filepath, skiprows=1, nrows=1, usecols=[1], header=None)[1][0] + origin = pd.read_excel( + filepath, skiprows=1, nrows=1, usecols=[1], header=None + )[1][0] # Remove any tzinfo to prevent future exceptions in pandas origin = origin.replace("CET", "") # Parse datetime object from timestamp @@ -819,7 +841,8 @@

Classes

Returns: DataFrame containing the wavelength and intensity data. """ - df = pd.read_csv(filepath, sep="\t", skiprows=14, names=["wavelength", "intensity"]) + df = pd.read_csv(filepath, sep="\t", skiprows=14, + names=["wavelength", "intensity"]) return df @staticmethod @@ -832,7 +855,8 @@

Classes

backward_counts = np.flip(np.stack(split_array[1::2]), axis=1) return forward_counts, backward_counts - def read_pixelscanner_data(self, filepath: Path) -> (pySPM.SPM_image, pySPM.SPM_image): + def read_pixelscanner_data(self, filepath: Path) -> ( + pySPM.SPM_image, pySPM.SPM_image): """ Read data from a PixelScanner measurement. Args: @@ -851,7 +875,8 @@

Classes

fwd, bwd = self.__get_forward_backward_counts(df["count_rates"], num_pixels) except KeyError: try: - fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], num_pixels) + fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], + num_pixels) except KeyError: # Support old data format fwd = df["forward (cps)"].to_numpy().reshape(num_pixels, num_pixels) @@ -970,7 +995,7 @@

Returns

""" Read a qudi confocal data file into a pandas DataFrame for analysis. """ confocal_params = self.read_qudi_parameters(filepath) data = self.read_into_ndarray(filepath, delimiter="\t") - # Use the confocal parameters to generate the index and columns for the DataFrame + # Use the confocal parameters to generate the index & columns for the DataFrame index = np.linspace( confocal_params['X image min (m)'], confocal_params['X image max (m)'], @@ -1046,7 +1071,8 @@

Returns

""" with open(filepath) as handle: # Generate column names for DataFrame by parsing the file - *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), handle) + *_comments, names = itertools.takewhile(lambda line: line.startswith('#'), + handle) names = names[1:].strip().split("\t") return pd.read_csv(filepath, names=names, comment="#", sep="\t")
@@ -1109,7 +1135,9 @@

Returns

DataFrame containing the data. """ # Extract only the origin timestamp - origin = pd.read_excel(filepath, skiprows=1, nrows=1, usecols=[1], header=None)[1][0] + origin = pd.read_excel( + filepath, skiprows=1, nrows=1, usecols=[1], header=None + )[1][0] # Remove any tzinfo to prevent future exceptions in pandas origin = origin.replace("CET", "") # Parse datetime object from timestamp @@ -1204,11 +1232,8 @@

Returns

pass else: label, value, _ = line.split("\t") - try: - # Convert strings to number where possible + with contextlib.suppress(ValueError): value = float(value) - except ValueError: - pass if "Oscillation Control>" in label: label = label.replace("Oscillation Control>", "") parameters[label] = value @@ -1272,7 +1297,8 @@

Returns

Returns: DataFrame containing the wavelength and intensity data. """ - df = pd.read_csv(filepath, sep="\t", skiprows=14, names=["wavelength", "intensity"]) + df = pd.read_csv(filepath, sep="\t", skiprows=14, + names=["wavelength", "intensity"]) return df
@@ -1331,7 +1357,8 @@

Returns

Expand source code -
def read_pixelscanner_data(self, filepath: Path) -> (pySPM.SPM_image, pySPM.SPM_image):
+
def read_pixelscanner_data(self, filepath: Path) -> (
+        pySPM.SPM_image, pySPM.SPM_image):
     """ Read data from a PixelScanner measurement.
 
     Args:
@@ -1350,7 +1377,8 @@ 

Returns

fwd, bwd = self.__get_forward_backward_counts(df["count_rates"], num_pixels) except KeyError: try: - fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], num_pixels) + fwd, bwd = self.__get_forward_backward_counts(df["Count Rates (cps)"], + num_pixels) except KeyError: # Support old data format fwd = df["forward (cps)"].to_numpy().reshape(num_pixels, num_pixels) @@ -1394,7 +1422,7 @@

Returns

""" Read raw .pys data files into a dictionary. """ byte_dict = np.load(str(filepath), encoding="bytes", allow_pickle=True) # Convert byte string keys to normal strings - return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict.keys()}
+ return {key.decode('utf8'): byte_dict.get(key) for key in byte_dict}
@@ -1438,13 +1466,16 @@

Returns

# Add params to dictionary label, value = line.split(":") if value != "\n": - params[label] = ast.literal_eval(inspect.cleandoc(value)) + params[label] = ast.literal_eval( + inspect.cleandoc(value)) elif line.count(":") == 3: # Handle files with timestamps in them label = line.split(":")[0] timestamp_str = "".join(line.split(":")[1:]).strip() - datetime_str = datetime.datetime.strptime(timestamp_str, "%d.%m.%Y %Hh%Mmin%Ss").replace( - tzinfo=datetime.timezone.utc) + datetime_str = datetime.datetime.strptime( + timestamp_str, + "%d.%m.%Y %Hh%Mmin%Ss" + ).replace(tzinfo=datetime.timezone.utc) params[label] = datetime_str except Exception as _: pass diff --git a/docs/qudi_hira_analysis/measurement_dataclass.html b/docs/qudi_hira_analysis/measurement_dataclass.html index 001698f..0905300 100644 --- a/docs/qudi_hira_analysis/measurement_dataclass.html +++ b/docs/qudi_hira_analysis/measurement_dataclass.html @@ -31,18 +31,20 @@

Module qudi_hira_analysis.measurement_dataclassModule qudi_hira_analysis.measurement_dataclassModule qudi_hira_analysis.measurement_dataclassModule qudi_hira_analysis.measurement_dataclassModule qudi_hira_analysis.measurement_dataclassModule qudi_hira_analysis.measurement_dataclassModule qudi_hira_analysis.measurement_dataclassInstance variables

__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) + _xy_position: tuple[int, int] = field(default=None) def __post_init__(self): self.log = logging.getLogger(__name__) @@ -383,7 +394,8 @@

Instance variables

self.filename = self.filepath.name def __repr__(self) -> str: - return f"MeasurementDataclass(timestamp='{self.timestamp}', filename='{self.filename}')" + return (f"MeasurementDataclass(timestamp='{self.timestamp}', " + f"filename='{self.filename}')") @property def data(self) -> np.ndarray | pd.DataFrame: @@ -425,12 +437,12 @@

Instance variables

self._fit_model = fit_model @property - def xy_position(self) -> Tuple[int, int]: + 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]): + def xy_position(self, xy_position: tuple[int, int]): self._xy_position = xy_position def get_param_from_filename(self, unit: str) -> float | None: @@ -471,10 +483,15 @@

Instance variables

# Handle exponents in filename if filename[params.start() - 1] == "e": try: - params = re.search(rf"(-?_\d)[^a]+?(?={unit})", filename).group(0)[1:] + params = re.search( + rf"(-?_\d)[^a]+?(?={unit})", filename + ).group(0)[1:] return float(params) - except AttributeError: - raise Exception(f"Parameter with unit '{unit}' not found in filename '{filename}'") + 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: @@ -490,7 +507,8 @@

Instance variables

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["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) @@ -575,7 +593,7 @@

Instance variables

return self.__params
-
var xy_position : Tuple[int, int]
+
var xy_position : tuple[int, int]

(row, col) position of measurement in image

@@ -583,7 +601,7 @@

Instance variables

Expand source code
@property
-def xy_position(self) -> Tuple[int, int]:
+def xy_position(self) -> tuple[int, int]:
     """ (row, col) position of measurement in image """
     return self._xy_position
@@ -664,10 +682,15 @@

Examples

# Handle exponents in filename if filename[params.start() - 1] == "e": try: - params = re.search(rf"(-?_\d)[^a]+?(?={unit})", filename).group(0)[1:] + params = re.search( + rf"(-?_\d)[^a]+?(?={unit})", filename + ).group(0)[1:] return float(params) - except AttributeError: - raise Exception(f"Parameter with unit '{unit}' not found in filename '{filename}'") + 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: @@ -693,7 +716,8 @@

Examples

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["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) @@ -797,11 +821,13 @@

Instance variables

timetrace: RawTimetrace = field(default=None) def __post_init__(self): - self.base_filename = self.measurement.filepath.name.replace("_pulsed_measurement.dat", "") + 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"))
+ return Image.open( + str(self.measurement.filepath).replace(".dat","_fig.png"))

Class variables

@@ -821,7 +847,7 @@

Class variables

Methods

-def show_image(self) ‑> Image +def show_image(self) ‑> 

Use PIL to open the measurement image saved on the disk

@@ -831,7 +857,8 @@

Methods

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"))
+ return Image.open( + str(self.measurement.filepath).replace(".dat","_fig.png"))