Basic Loading Tutorial
This tutorial covers the fundamentals of loading EPR data with EPyR Tools.
Interactive Notebook
File: examples/notebooks/01_Basic_Loading.ipynb
The most comprehensive way to learn basic loading is through our interactive Jupyter notebook. It provides:
Step-by-step guidance with explanations
Real EPR data examples
Interactive code cells you can modify
Troubleshooting help and error handling
To run the notebook:
cd examples/notebooks
jupyter notebook 01_Basic_Loading.ipynb
Core Concepts
File Formats
EPyR Tools supports two main Bruker file formats:
- BES3T Format (Modern Bruker)
.dscfiles contain parameters and metadata.dtafiles contain the actual spectral dataAlways come as pairs - both files needed
- ESP Format (Legacy Bruker)
.parfiles contain parameters.spcfiles contain spectral dataAlso come as pairs
Data Types
EPR data can be:
- 1D Data
Single spectrum vs magnetic field
Returns: x (field array), y (intensity array)
Example: CW-EPR spectrum
- 2D Data
Parameter-dependent spectra (time, power, angle, etc.)
Returns: x (list of axes), y (2D intensity matrix)
Example: Rabi oscillation, ENDOR
- Complex vs Real
Pulsed EPR often produces complex data (I/Q detection)
CW-EPR typically produces real data
Complex data visualization uses magnitude:
np.abs(data)
Basic Usage Examples
Simple Loading
import epyr
# Open file dialog to select data
x, y, params, filepath = epyr.eprload()
# Or specify file directly
x, y, params, filepath = epyr.eprload('path/to/spectrum.dsc')
# Check what you loaded
print(f"Loaded: {filepath}")
if isinstance(x, list):
print(f"2D data: {y.shape}")
else:
print(f"1D data: {len(y)} points")
Handling Different Data Types
import numpy as np
import matplotlib.pyplot as plt
# Load data
x, y, params, filepath = epyr.eprload('example.dsc')
if isinstance(x, list) and len(x) > 1:
# 2D data
print(f"2D EPR data: {y.shape}")
print(f"Complex data: {np.iscomplexobj(y)}")
# For visualization, use magnitude if complex
y_plot = np.abs(y) if np.iscomplexobj(y) else y
# Plot as 2D color map
plt.figure(figsize=(10, 6))
plt.imshow(y_plot, aspect='auto', origin='lower', cmap='viridis')
plt.colorbar(label='Signal (a.u.)')
plt.xlabel('Field Points')
plt.ylabel('Parameter Points')
plt.title('2D EPR Data')
plt.show()
else:
# 1D data
x_array = x[0] if isinstance(x, list) else x
print(f"1D EPR data: {len(x_array)} points")
print(f"Field range: {x_array.min():.1f} - {x_array.max():.1f} G")
# Simple 1D plot
plt.figure(figsize=(10, 6))
plt.plot(x_array, y, 'b-', linewidth=1.5)
plt.xlabel('Magnetic Field (G)')
plt.ylabel('EPR Signal (a.u.)')
plt.title('EPR Spectrum')
plt.grid(True, alpha=0.3)
plt.show()
Parameter Extraction
# Common EPR parameters
key_params = {
'MWFQ': 'Microwave Frequency (Hz)',
'MWPW': 'Microwave Power (dB)',
'HCF': 'Center Field (G)',
'HSW': 'Sweep Width (G)',
'AVGS': 'Number of Averages',
'TE': 'Temperature (K)',
'MA': 'Modulation Amplitude (G)',
}
print("📋 Experimental Parameters:")
for param, description in key_params.items():
if param in params:
value = params[param]
print(f" {description}: {value}")
# Calculate derived quantities
if 'MWFQ' in params and 'HCF' in params:
freq_ghz = float(params['MWFQ']) / 1e9
field_g = float(params['HCF'])
# Approximate g-factor at center field
h = 6.626e-34 # Planck constant
mu_b = 9.274e-24 # Bohr magneton
g_factor = (h * freq_ghz * 1e9) / (mu_b * field_g * 1e-4)
print(f" Center g-factor: {g_factor:.3f}")
Error Handling
Robust Loading
def safe_load_epr(file_path):
"""Safely load EPR data with error handling."""
try:
x, y, params, filepath = epyr.eprload(file_path)
if x is None or y is None:
print(f"❌ Failed to load data from {file_path}")
return None
print(f"✅ Successfully loaded {file_path}")
return x, y, params, filepath
except FileNotFoundError:
print(f"❌ File not found: {file_path}")
except Exception as e:
print(f"❌ Error loading {file_path}: {e}")
return None
# Usage
result = safe_load_epr('spectrum.dsc')
if result is not None:
x, y, params, filepath = result
# Continue with analysis...
Common Issues
Missing .dta or .spc file
from pathlib import Path
def check_file_pairs(dsc_file):
"""Check if required data file exists."""
dsc_path = Path(dsc_file)
if dsc_path.suffix.lower() == '.dsc':
dta_file = dsc_path.with_suffix('.dta')
if not dta_file.exists():
print(f"❌ Missing data file: {dta_file}")
return False
elif dsc_path.suffix.lower() == '.par':
spc_file = dsc_path.with_suffix('.spc')
if not spc_file.exists():
print(f"❌ Missing data file: {spc_file}")
return False
return True
Case sensitivity issues
def find_epr_files(directory):
"""Find EPR files handling case variations."""
from pathlib import Path
data_dir = Path(directory)
epr_files = []
# Check both upper and lower case
for pattern in ['*.dsc', '*.DSC', '*.par', '*.PAR']:
epr_files.extend(data_dir.glob(pattern))
return epr_files
Data Export
Simple Export
import pandas as pd
# Export 1D data to CSV
if not isinstance(x, list):
df = pd.DataFrame({
'Field_G': x,
'Intensity': y
})
df.to_csv('spectrum.csv', index=False)
print("✅ Data exported to spectrum.csv")
# Export parameters to JSON
import json
with open('parameters.json', 'w') as f:
json.dump(params, f, indent=2)
Batch Processing
from pathlib import Path
def process_directory(data_dir):
"""Process all EPR files in a directory."""
results = {}
for epr_file in Path(data_dir).glob('*.dsc'):
print(f"Processing {epr_file.name}...")
result = safe_load_epr(epr_file)
if result is not None:
x, y, params, filepath = result
# Store basic info
results[epr_file.stem] = {
'data_type': '2D' if isinstance(x, list) and len(x) > 1 else '1D',
'complex': np.iscomplexobj(y),
'shape': y.shape,
'frequency': params.get('MWFQ', 'Unknown'),
'temperature': params.get('TE', 'Unknown')
}
return results
# Process all files
results = process_directory('examples/data')
for filename, info in results.items():
print(f"{filename}: {info['data_type']} data, shape {info['shape']}")
Best Practices
Always check data validity
if x is None or y is None: print("Failed to load data") return
Handle both 1D and 2D data
if isinstance(x, list) and len(x) > 1: # 2D data processing pass else: # 1D data processing pass
Use magnitude for complex data visualization
y_display = np.abs(y) if np.iscomplexobj(y) else y
Preserve metadata
# Always keep parameters for reproducibility analysis_info = { 'original_file': str(filepath), 'parameters': params, 'processing_date': datetime.now().isoformat() }
Validate critical parameters
required_params = ['MWFQ', 'HCF', 'HSW'] missing = [p for p in required_params if p not in params] if missing: print(f"Warning: Missing parameters {missing}")
Next Steps
After mastering basic loading:
Try Baseline Correction: Learn to remove baseline drift
Explore FAIR Conversion: Convert data to open formats
Advanced Visualization: Create publication-quality plots
Quantitative Analysis: Extract g-factors and coupling constants
Additional Resources
Example Scripts:
examples/scripts/01_basic_loading.pySample Data:
examples/data/contains real EPR measurementsAPI Reference: Complete function documentation
Community: GitHub issues and discussions for help