Example 1: Basic Workflow
Complete pipeline for analyzing a single tensile test specimen.
Scenario
You have a CSV file 316L_specimen_A1.csv containing tensile test data and want to calculate mechanical properties.
from tensile import TensileTest
# Create test instance and run full pipeline
test = (TensileTest()
.load("data/316L_specimen_A1.csv")
.validate()
.clean()
.segment()
.analyze())
# Print summary
print(test.summary())
# Export results
test.export("results/316L_A1_results.csv")
=== Tensile Test Analysis Summary === Specimen: 316L_specimen_A1.csv Young's Modulus (E): 193.45 GPa Yield Strength (Rp0.2): 280.32 MPa Ultimate Tensile Strength (Rm): 625.78 MPa Total Elongation (At): 45.23 % Elastic R²: 0.9998 Quality: Status: VALID Slippages detected: 1 Slippages corrected: 1 Warnings: 0
Step-by-Step Explanation
# 1. Load data from CSV
test = TensileTest()
test.load("data/316L_specimen_A1.csv")
# 2. Validate data quality
test.validate()
if not test.quality_report['is_valid']:
print("Validation failed!")
print(test.quality_report['validation_issues'])
# 3. Clean data (detect/correct errors)
test.clean()
print(f"Slippages detected: {test.quality_report['num_slippages_detected']}")
# 4. Segment into elastic/plastic regions
test.segment()
print(f"Elastic region: indices {test.segments['elastic_start']} to {test.segments['elastic_end']}")
# 5. Calculate mechanical properties
test.analyze()
print(f"Young's Modulus: {test.results['youngs_modulus_GPa']:.2f} GPa")
print(f"Yield Strength: {test.results['Rp02_MPa']:.2f} MPa")
print(f"UTS: {test.results['Rm_MPa']:.2f} MPa")
print(f"Elongation: {test.results['At_percent']:.2f}%")
Example 2: Batch Processing
Process multiple test specimens from a folder and generate a comprehensive Excel report.
Scenario
You have 10 specimens in folder data/316L_batch_A/ and need summary statistics with outlier detection.
from tensile import TensileTestBatch
# Load all CSV files from folder
batch = TensileTestBatch.from_folder("data/316L_batch_A/")
print(f"Loaded {len(batch.tests)} tests")
# Analyze all tests (parallel for speed)
batch.analyze_all(parallel=True)
# Get summary statistics
summary = batch.summary_statistics()
print("\n=== Summary Statistics ===")
print(summary)
# Identify outliers using Z-score method
outliers = batch.identify_outliers(method='zscore', threshold=2.5)
print("\n=== Outliers ===")
print(outliers[outliers['is_outlier']])
# Export comprehensive Excel report
batch.export_summary("reports/316L_batch_A_report.xlsx")
print("\nExcel report saved!")
Loaded 10 tests === Summary Statistics === Specimen E_GPa Rp02_MPa Rm_MPa At_percent Analysis_OK specimen_1.csv 192.3 278.5 623.4 44.5 True specimen_2.csv 194.1 281.2 627.8 45.8 True specimen_3.csv 193.8 279.8 625.2 45.1 True ... Mean 193.5 280.1 625.3 45.2 - Std 1.2 1.8 2.5 0.8 - CV% 0.6 0.6 0.4 1.8 - Min 191.8 277.2 621.1 43.9 - Max 195.2 282.9 628.7 46.3 - === Outliers === Specimen Property Value is_outlier specimen_8.csv Rm_MPa 631.5 True Excel report saved!
Processing Specific Files
# Process specific list of files
files = [
"data/specimen_1.csv",
"data/specimen_2.csv",
"data/specimen_3.csv"
]
batch = TensileTestBatch.from_csv_list(files)
batch.analyze_all()
summary = batch.summary_statistics()
print(summary)
Example 3: Custom Configuration
Customize analysis parameters for specific materials or test conditions.
Scenario
Testing aluminum alloy with more sensitive slippage detection and custom elastic range.
from tensile import TensileTest, TensileTestConfig
# Create custom configuration for aluminum
al_config = TensileTestConfig(
# More sensitive slippage detection
jump_threshold=0.00005,
min_strain_decrease_length=3,
# Aluminum-specific elastic range
elastic_strain_range=(0.0003, 0.0015),
# Use piecewise regression segmentation
segmentation_method='piecewise_regression',
# Custom plot settings
show_annotations=True,
show_slippages=True,
plot_width=1200,
plot_height=700
)
# Use configuration with single test
test = TensileTest(config=al_config)
test.load("data/AlSi10Mg_specimen.csv").validate().clean().segment().analyze()
print(f"Detected {test.quality_report['num_slippages_detected']} slippages")
print(f"Young's Modulus: {test.results['youngs_modulus_GPa']:.2f} GPa")
# Use same configuration for batch
batch = TensileTestBatch.from_folder("data/AlSi10Mg/", config=al_config)
batch.analyze_all()
summary = batch.summary_statistics()
print(summary)
Configuration Comparison
from tensile import TensileTestConfig
# Default configuration
default_config = TensileTestConfig()
# High-sensitivity configuration (detect subtle errors)
sensitive_config = TensileTestConfig(
jump_threshold=0.00001,
min_strain_decrease_length=2,
max_slippages_per_test=10
)
# Conservative configuration (only major errors)
conservative_config = TensileTestConfig(
jump_threshold=0.001,
min_strain_decrease_length=10,
max_slippages_per_test=3
)
# Manual segmentation (no automatic detection)
manual_config = TensileTestConfig(
segmentation_method='manual',
elastic_strain_range=(0.0005, 0.002)
)
Example 4: Visualization
Create publication-quality interactive plots for single tests and batch comparisons.
Scenario
Generate interactive plots with annotations for presentation or publication.
Single Test Visualization
from tensile import TensileTest
# Analyze test
test = (TensileTest()
.load("data/316L_specimen_A1.csv")
.validate()
.clean()
.segment()
.analyze())
# Create interactive plot with all features
fig = test.plot(
show_segments=True, # Highlight elastic region
show_properties=True, # Show Rp0.2 and Rm markers
show_slippages=True, # Mark slippage locations
title="316L Stainless Steel - Specimen A1",
width=1000,
height=700
)
# Display in browser
fig.show()
# Save to HTML (interactive)
fig.write_html("plots/316L_A1_interactive.html")
# Save to PNG (static, requires kaleido)
fig.write_image("plots/316L_A1.png", width=1200, height=800, scale=2)
Customizing Plots
# Get figure and customize
fig = test.plot()
# Modify layout
fig.update_layout(
title={
'text': "Custom Title",
'x': 0.5,
'xanchor': 'center',
'font': {'size': 24, 'family': 'Arial'}
},
xaxis_title="Engineering Strain (%)",
yaxis_title="Engineering Stress (MPa)",
font_family="Arial",
template="plotly_white",
showlegend=True,
legend=dict(
x=0.02,
y=0.98,
bgcolor="rgba(255,255,255,0.8)"
)
)
# Modify colors
fig.update_traces(
line=dict(color='darkblue', width=2),
selector=dict(name='Stress-Strain')
)
fig.show()
Example 5: Error Handling
Robust error handling and quality control in production environments.
Scenario
Processing files with potential errors, missing data, or invalid measurements.
from tensile import TensileTest
import os
def analyze_test_safely(filepath):
"""
Analyze a test with comprehensive error handling.
Returns (test, success, error_message).
"""
test = TensileTest()
try:
# Load data
if not os.path.exists(filepath):
return test, False, f"File not found: {filepath}"
test.load(filepath)
# Validate
test.validate()
if not test.quality_report['is_valid']:
issues = '; '.join(test.quality_report['validation_issues'])
return test, False, f"Validation failed: {issues}"
# Process with cleaning and segmentation
test.clean().segment().analyze()
# Check analysis success
if not test.results.get('analysis_successful', False):
return test, False, "Analysis failed to compute properties"
# Check for warnings
if test.quality_report['warnings']:
print(f"Warnings for {filepath}:")
for warning in test.quality_report['warnings']:
print(f" - {warning}")
return test, True, None
except FileNotFoundError as e:
return test, False, f"File error: {str(e)}"
except ValueError as e:
return test, False, f"Value error: {str(e)}"
except Exception as e:
return test, False, f"Unexpected error: {str(e)}"
# Use the safe function
files = ["specimen_1.csv", "specimen_2.csv", "specimen_3.csv"]
results = []
for filepath in files:
test, success, error = analyze_test_safely(filepath)
if success:
print(f"✓ {filepath}: E={test.results['youngs_modulus_GPa']:.2f} GPa")
results.append(test.results)
else:
print(f"✗ {filepath}: {error}")
print(f"\nSuccessfully analyzed {len(results)}/{len(files)} tests")
Batch Error Handling
from tensile import TensileTestBatch
# Load batch
batch = TensileTestBatch.from_folder("data/mixed_quality/")
# Analyze all (continues even if some fail)
batch.analyze_all()
# Get quality summary
quality = batch.quality_summary()
# Filter valid and invalid tests
valid_tests = [t for t in batch.tests if t.quality_report['is_valid']]
invalid_tests = [t for t in batch.tests if not t.quality_report['is_valid']]
print(f"Valid: {len(valid_tests)}, Invalid: {len(invalid_tests)}")
# Report issues
for test in invalid_tests:
filename = test.metadata.get('filename', 'Unknown')
print(f"\n{filename}:")
if test.quality_report['errors']:
print(" Errors:")
for error in test.quality_report['errors']:
print(f" - {error}")
if test.quality_report['validation_issues']:
print(" Validation Issues:")
for issue in test.quality_report['validation_issues']:
print(f" - {issue}")
# Export only valid tests
if valid_tests:
valid_batch = TensileTestBatch()
valid_batch.tests = valid_tests
valid_batch.export_summary("valid_tests_only.xlsx")
Example 6: Working with Metadata
Add and use metadata for organizing and filtering test results.
Scenario
Organize tests by material, batch, orientation, and test conditions.
from tensile import TensileTest, TensileTestBatch
# Add metadata during loading
test = TensileTest.from_csv(
"specimen.csv",
metadata={
'material': '316L',
'batch': 'A',
'specimen_id': '1',
'orientation': 'horizontal',
'test_date': '2026-01-15',
'test_temperature': 20,
'test_speed_mm_min': 2.0,
'operator': 'Jane Smith',
'machine': 'Instron_5982'
}
)
test.validate().clean().segment().analyze()
# Metadata is included in exports
test.export("results_with_metadata.csv", include_metadata=True)
# Use metadata in analysis
print(f"Material: {test.metadata['material']}")
print(f"Batch: {test.metadata['batch']}")
print(f"E = {test.results['youngs_modulus_GPa']:.2f} GPa")
Batch Metadata Analysis
import pandas as pd
from tensile import TensileTestBatch
# Load batch
batch = TensileTestBatch.from_folder("data/multi_batch/")
batch.analyze_all()
# Extract metadata and results into DataFrame
data = []
for test in batch.tests:
if test.results.get('analysis_successful'):
row = {
'material': test.metadata.get('material'),
'batch': test.metadata.get('batch'),
'orientation': test.metadata.get('orientation'),
'E_GPa': test.results['youngs_modulus_GPa'],
'Rp02_MPa': test.results['Rp02_MPa'],
'Rm_MPa': test.results['Rm_MPa'],
'At_percent': test.results['At_percent']
}
data.append(row)
df = pd.DataFrame(data)
# Group by batch
batch_stats = df.groupby('batch').agg({
'E_GPa': ['mean', 'std'],
'Rp02_MPa': ['mean', 'std'],
'Rm_MPa': ['mean', 'std']
})
print(batch_stats)
# Group by orientation
orientation_stats = df.groupby('orientation').mean()
print(orientation_stats)
Automatic Metadata Loading
# If you have companion metadata files (.id_metal or .is_metal)
# they are automatically loaded
test = TensileTest()
test.load("specimen.csv", load_metadata=True) # Default behavior
# Metadata from companion files is now available
print(test.metadata)
# {'filepath': '...', 'filename': 'specimen.csv', 'material': '316L', ...}
Example 7: Quality Control Workflow
Comprehensive quality control for production testing laboratories.
Scenario
QC workflow with automated acceptance criteria, outlier flagging, and report generation.
from tensile import TensileTestBatch
import pandas as pd
# Define acceptance criteria for 316L stainless steel
ACCEPTANCE_CRITERIA = {
'youngs_modulus_GPa': (180, 210),
'Rp02_MPa': (250, 350),
'Rm_MPa': (550, 700),
'At_percent': (35, 60)
}
def check_acceptance(test, criteria):
"""Check if test results meet acceptance criteria."""
if not test.results.get('analysis_successful'):
return False, ['Analysis failed']
failures = []
for prop, (min_val, max_val) in criteria.items():
value = test.results.get(prop)
if value is None:
failures.append(f"{prop}: not calculated")
elif value < min_val:
failures.append(f"{prop}: {value:.2f} below minimum {min_val}")
elif value > max_val:
failures.append(f"{prop}: {value:.2f} above maximum {max_val}")
return len(failures) == 0, failures
# Load and analyze batch
batch = TensileTestBatch.from_folder("data/316L_production/")
batch.analyze_all()
# Quality control report
qc_data = []
for test in batch.tests:
filename = test.metadata.get('filename', 'Unknown')
# Check acceptance
accepted, failures = check_acceptance(test, ACCEPTANCE_CRITERIA)
# Compile QC data
qc_row = {
'Specimen': filename,
'Valid': test.quality_report['is_valid'],
'Complete': test.quality_report.get('is_complete', False),
'Slippages': test.quality_report['num_slippages_detected'],
'Accepted': accepted,
'Failures': '; '.join(failures) if failures else 'None',
'E_GPa': test.results.get('youngs_modulus_GPa'),
'Rp02_MPa': test.results.get('Rp02_MPa'),
'Rm_MPa': test.results.get('Rm_MPa'),
'At_percent': test.results.get('At_percent')
}
qc_data.append(qc_row)
# Create QC DataFrame
qc_df = pd.DataFrame(qc_data)
# Summary statistics
total = len(qc_df)
valid = qc_df['Valid'].sum()
complete = qc_df['Complete'].sum()
accepted = qc_df['Accepted'].sum()
print("=== Quality Control Summary ===")
print(f"Total tests: {total}")
print(f"Valid: {valid} ({valid/total*100:.1f}%)")
print(f"Complete: {complete} ({complete/total*100:.1f}%)")
print(f"Accepted: {accepted} ({accepted/total*100:.1f}%)")
print(f"\nRejected tests:")
print(qc_df[~qc_df['Accepted']][['Specimen', 'Failures']])
# Export QC report
qc_df.to_excel("QC_Report_316L.xlsx", index=False)
print("\nQC report exported to QC_Report_316L.xlsx")
Example 8: Advanced Usage
Advanced techniques for custom analysis and integration.
Custom Property Calculations
import numpy as np
from tensile import TensileTest
# Standard analysis
test = (TensileTest()
.load("specimen.csv")
.validate()
.clean()
.segment()
.analyze())
# Add custom calculations
strain = test.cleaned_data[test._strain_col].values
stress = test.cleaned_data[test._stress_col].values
# Calculate toughness (area under entire curve)
toughness = np.trapz(stress, strain)
test.results['toughness_MJ_m3'] = toughness
# Calculate resilience (area under elastic curve)
elastic_end = test.segments['elastic_end']
resilience = np.trapz(stress[:elastic_end], strain[:elastic_end])
test.results['resilience_MJ_m3'] = resilience
# Calculate strain hardening exponent (n-value)
# From plastic region: σ = K * ε^n
plastic_start = test.segments.get('yield_index', 0)
rm_index = np.argmax(stress)
plastic_strain = strain[plastic_start:rm_index]
plastic_stress = stress[plastic_start:rm_index]
if len(plastic_strain) > 10:
# Log-log fit
log_strain = np.log(plastic_strain + 0.002) # Offset to avoid log(0)
log_stress = np.log(plastic_stress)
from scipy.stats import linregress
result = linregress(log_strain, log_stress)
n_value = result.slope
k_value = np.exp(result.intercept)
test.results['strain_hardening_exponent_n'] = n_value
test.results['strength_coefficient_K_MPa'] = k_value
print(f"Toughness: {test.results['toughness_MJ_m3']:.2f} MJ/m³")
print(f"Resilience: {test.results['resilience_MJ_m3']:.4f} MJ/m³")
print(f"Strain hardening exponent (n): {test.results.get('strain_hardening_exponent_n', 'N/A')}")
print(f"Strength coefficient (K): {test.results.get('strength_coefficient_K_MPa', 'N/A'):.1f} MPa")
Integration with Other Libraries
from tensile import TensileTestBatch
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
# Load and analyze batch
batch = TensileTestBatch.from_folder("data/316L_batch/")
batch.analyze_all()
# Extract data for statistical analysis
data = []
for test in batch.tests:
if test.results.get('analysis_successful'):
data.append({
'E': test.results['youngs_modulus_GPa'],
'Rp02': test.results['Rp02_MPa'],
'Rm': test.results['Rm_MPa'],
'At': test.results['At_percent']
})
df = pd.DataFrame(data)
# Statistical analysis with seaborn
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Histograms
sns.histplot(df['E'], kde=True, ax=axes[0, 0])
axes[0, 0].set_title("Young's Modulus Distribution")
axes[0, 0].set_xlabel("E (GPa)")
sns.histplot(df['Rp02'], kde=True, ax=axes[0, 1])
axes[0, 1].set_title("Yield Strength Distribution")
axes[0, 1].set_xlabel("Rp0.2 (MPa)")
sns.histplot(df['Rm'], kde=True, ax=axes[1, 0])
axes[1, 0].set_title("UTS Distribution")
axes[1, 0].set_xlabel("Rm (MPa)")
sns.histplot(df['At'], kde=True, ax=axes[1, 1])
axes[1, 1].set_title("Elongation Distribution")
axes[1, 1].set_xlabel("At (%)")
plt.tight_layout()
plt.savefig("statistical_analysis.png", dpi=300)
plt.show()
# Correlation matrix
correlation = df.corr()
print("\nCorrelation Matrix:")
print(correlation)
# Box plots for outlier visualization
fig, ax = plt.subplots(1, 4, figsize=(16, 4))
for i, col in enumerate(['E', 'Rp02', 'Rm', 'At']):
sns.boxplot(y=df[col], ax=ax[i])
ax[i].set_title(col)
plt.tight_layout()
plt.savefig("box_plots.png", dpi=300)
plt.show()
Exporting for External Tools
from tensile import TensileTestBatch
import json
batch = TensileTestBatch.from_folder("data/")
batch.analyze_all()
# Export to JSON for web applications
json_data = []
for test in batch.tests:
if test.results.get('analysis_successful'):
json_data.append({
'filename': test.metadata.get('filename'),
'material': test.metadata.get('material'),
'results': {
'E': float(test.results['youngs_modulus_GPa']),
'Rp02': float(test.results['Rp02_MPa']),
'Rm': float(test.results['Rm_MPa']),
'At': float(test.results['At_percent'])
},
'quality': {
'valid': bool(test.quality_report['is_valid']),
'slippages': int(test.quality_report['num_slippages_detected'])
}
})
with open("results.json", "w") as f:
json.dump(json_data, f, indent=2)
print("Exported to results.json")