Library Usage Examples¶
This section provides comprehensive examples of how to use the OptiScope library for optimization analysis and visualization.
Quick Navigation¶
Choose a topic to explore detailed examples:
📥 Loading Data¶
Learn how to load optimization results from various file formats (CSV, JSON, HDF5, Parquet) and work with the OptiScope data model.
Topics covered: - Loading from different formats - Using the format registry - Saving results - Loading multiple files - Understanding the data structure
📊 Working with Result Sets¶
Understand how to organize and track different subsets of solutions using result sets.
Topics covered: - Creating result sets manually and from analysis - Accessing and managing result sets - Comparing result sets - Using result sets in visualizations - Best practices
🔍 Analysis Examples¶
Comprehensive guide to using OptiScope's analysis tools to extract insights from optimization results.
Topics covered: - Pareto Front Identification - Finding non-dominated solutions - Smart Pareto Filter - Reducing large Pareto fronts to representative subsets - TOPSIS - Multi-criteria decision analysis and ranking - Knee Point Detection - Finding best compromise solutions - Combining Analysis Tools - Complete analysis workflows
📈 Visualization Examples¶
Learn how to create powerful interactive visualizations to explore your optimization results.
Topics covered: - Parallel Coordinates - High-dimensional data exploration - Scatter Plot Matrix (SPLOM) - Pairwise variable relationships - Correlation Heatmap - Variable dependencies - Pareto Front Visualization - 2D and 3D Pareto front plots - Optimization History - Tracking convergence over iterations - Large Dataset Visualization - Resampled plots for big data - Customization and Export - Creating publication-quality figures
🚀 Complete Workflow¶
A comprehensive end-to-end example demonstrating the full power of OptiScope.
Workflow includes: 1. Loading optimization results 2. Identifying the Pareto front 3. Filtering to a representative subset 4. Ranking solutions with TOPSIS 5. Detecting knee points 6. Creating result sets 7. Comprehensive visualization 8. Saving results and reports
🔧 Custom File Handlers¶
Learn how to create custom file handlers for proprietary or specialized data formats.
Topics covered: - Implementing custom handlers - Registering handlers - Reading and writing custom formats - Best practices
Getting Started¶
If you're new to OptiScope, we recommend following this learning path:
- Start with Loading Data to understand how to get your optimization results into OptiScope
- Learn about Result Sets to organize your solutions
- Explore Analysis Examples to extract insights from your data
- Create Visualizations to understand and present your results
- Review the Complete Workflow to see how everything fits together
Quick Example¶
Here's a minimal example to get you started:
from optiscope import load_results
from optiscope.analysis import identify_pareto_front, topsis
from optiscope.plotting import plot_parallel_coordinates
import numpy as np
# Load data
result = load_results("optimization_results.csv")
# Find Pareto front
pareto_mask = identify_pareto_front(
objectives=result.objectives,
directions=result.optimization_directions
)
# Rank with TOPSIS
scores = topsis(
objectives=result.objectives[pareto_mask],
weights=[0.4, 0.3, 0.3],
directions=result.optimization_directions
)
# Visualize
fig = plot_parallel_coordinates(result)
fig.show()
For more detailed examples, explore the sections above!
Need Help?¶
- Check the User Guide for conceptual explanations
- Browse the API Reference for detailed function documentation
- Try the Dash App for interactive analysis without coding
Loading Data¶
OptiScope supports loading data from various formats like CSV and JSON.
from optiscope.io.csv_handler import CSVHandler
from optiscope.io.json_handler import JSONHandler
# Load from CSV
csv_handler = CSVHandler()
result = csv_handler.read("path/to/results.csv")
# Load from JSON
json_handler = JSONHandler()
result = json_handler.read("path/to/results.json")
Working with Result Sets¶
The ResultSet class represents a subset of points within an optimization result, allowing you to organize and track different groups of solutions.
from optiscope.core.result_set import ResultSet
import numpy as np
# Create a result set manually
custom_set = ResultSet(
name="high_efficiency",
indices=[0, 5, 10, 15], # Indices of solutions in the result
created_by="manual_selection",
description="Solutions with efficiency > 0.8"
)
# Add the set to your result
result.add_set(custom_set)
# Access result sets
print(result.sets) # Dictionary of all result sets
Analysis Tools¶
Pareto Front Identification¶
Identify non-dominated solutions from your optimization results.
from optiscope.analysis import identify_pareto_front
from optiscope.core.result_set import ResultSet
import numpy as np
# Identify Pareto-optimal solutions
pareto_mask = identify_pareto_front(
objectives=result.objectives,
directions=result.optimization_directions
)
print(f"Found {pareto_mask.sum()} Pareto-optimal solutions out of {len(result.objectives)}")
# Create a result set from the Pareto front
pareto_set = ResultSet(
name="pareto_front",
indices=np.where(pareto_mask)[0].tolist(),
created_by="pareto_analysis",
description="Non-dominated solutions"
)
# Add to result
result.add_set(pareto_set)
# Access Pareto solutions
pareto_objectives = result.objectives[pareto_mask]
print(f"Pareto front objectives:\n{pareto_objectives}")
Smart Pareto Filter¶
When your Pareto front contains too many solutions, use the Smart Pareto Filter to reduce it to a representative subset.
from optiscope.analysis import smart_pareto_filter, adaptive_smart_pareto_filter
import numpy as np
# First, get the Pareto front
pareto_mask = identify_pareto_front(
objectives=result.objectives,
directions=result.optimization_directions
)
pareto_indices = np.where(pareto_mask)[0]
pareto_objectives = result.objectives[pareto_indices]
print(f"Pareto front has {len(pareto_objectives)} solutions")
# Option 1: Manual epsilon specification
# Epsilon controls the minimum separation between selected points
filtered_indices = smart_pareto_filter(
objectives=pareto_objectives,
epsilon=0.05, # 5% minimum separation in normalized space
normalize=True
)
print(f"Smart Pareto Filter reduced to {len(filtered_indices)} solutions")
# Map back to original indices
final_indices = pareto_indices[filtered_indices]
# Option 2: Adaptive - automatically determines epsilon
# This is easier to use when you have a target reduction in mind
filtered_indices_adaptive = adaptive_smart_pareto_filter(
objectives=pareto_objectives,
target_reduction=0.5, # Reduce to 50% of original
min_points=10, # Keep at least 10 points
max_points=50, # Keep at most 50 points
normalize=True
)
print(f"Adaptive filter reduced to {len(filtered_indices_adaptive)} solutions")
# Create a result set for the filtered Pareto front
filtered_pareto_set = ResultSet(
name="filtered_pareto",
indices=pareto_indices[filtered_indices_adaptive].tolist(),
created_by="smart_pareto_filter",
description=f"Representative subset of Pareto front ({len(filtered_indices_adaptive)} points)"
)
result.add_set(filtered_pareto_set)
TOPSIS (Multi-Criteria Decision Analysis)¶
Use TOPSIS to rank solutions based on your preferences (weights).
from optiscope.analysis import topsis, topsis_from_result, compare_weight_scenarios
import numpy as np
# Basic TOPSIS with custom weights
# Weights should sum to 1.0 and represent the relative importance of each objective
scores = topsis(
objectives=result.objectives,
weights=[0.4, 0.3, 0.3], # 40% weight on first objective, 30% on others
directions=result.optimization_directions,
normalize_method="vector" # or "minmax"
)
# Get the best solution according to TOPSIS
best_idx = np.argmax(scores)
print(f"Best solution index: {best_idx}")
print(f"TOPSIS score: {scores[best_idx]:.3f}")
print(f"Objectives: {result.objectives.iloc[best_idx]}")
# Get detailed results including ranking
details = topsis(
objectives=result.objectives,
weights=[0.4, 0.3, 0.3],
directions=result.optimization_directions,
return_details=True
)
print(f"\nTop 5 solutions:")
for i, idx in enumerate(details['ranking'][:5]):
print(f"{i+1}. Index {idx}: Score = {details['scores'][idx]:.3f}")
# Compare different weight scenarios
# Useful when different stakeholders have different priorities
scenarios = {
"Cost-focused": np.array([0.6, 0.2, 0.2]),
"Performance-focused": np.array([0.2, 0.6, 0.2]),
"Balanced": np.array([0.33, 0.33, 0.34])
}
comparison = compare_weight_scenarios(
objectives=result.objectives,
weight_scenarios=scenarios,
directions=result.optimization_directions
)
print("\nTop solution for each scenario:")
print(comparison)
Combining Analysis Tools¶
The real power comes from combining multiple analysis tools in a workflow.
from optiscope.analysis import (
identify_pareto_front,
adaptive_smart_pareto_filter,
topsis,
detect_knee_points
)
import numpy as np
# Step 1: Identify Pareto front
pareto_mask = identify_pareto_front(
objectives=result.objectives,
directions=result.optimization_directions
)
pareto_indices = np.where(pareto_mask)[0]
print(f"Step 1: Found {len(pareto_indices)} Pareto-optimal solutions")
# Step 2: Apply Smart Pareto Filter to reduce complexity
# Note: we use iloc for pandas indexing
filtered_indices = adaptive_smart_pareto_filter(
objectives=result.objectives.iloc[pareto_indices],
target_reduction=0.3, # Reduce to 30% of Pareto front
min_points=10,
normalize=True
)
final_indices = pareto_indices[filtered_indices]
print(f"Step 2: Reduced to {len(final_indices)} representative solutions")
# Step 3: Use TOPSIS to rank the filtered solutions
scores = topsis(
objectives=result.objectives.iloc[final_indices],
weights=[0.4, 0.3, 0.3],
directions=result.optimization_directions
)
# Get top 3 solutions
top_3_in_filtered = np.argsort(scores)[-3:][::-1]
top_3_indices = final_indices[top_3_in_filtered]
print(f"\nTop 3 recommended solutions:")
for i, idx in enumerate(top_3_indices):
print(f"{i+1}. Index {idx}: TOPSIS score = {scores[top_3_in_filtered[i]]:.3f}")
print(f" Objectives: {result.objectives.iloc[idx]}")
# Create result sets for each stage
result.add_set(ResultSet(
name="pareto_front",
indices=pareto_indices.tolist(),
created_by="analysis_workflow",
description="All Pareto-optimal solutions"
))
result.add_set(ResultSet(
name="filtered_pareto",
indices=final_indices.tolist(),
created_by="analysis_workflow",
description="Representative Pareto subset"
))
result.add_set(ResultSet(
name="top_3_recommended",
indices=top_3_indices.tolist(),
created_by="analysis_workflow",
description="Top 3 solutions by TOPSIS"
))
Visualization¶
OptiScope provides several powerful plotting functions for exploring optimization results.
Parallel Coordinates Plot¶
Parallel coordinates are excellent for visualizing high-dimensional data and exploring trade-offs.
from optiscope.plotting import plot_parallel_coordinates
# Basic usage - shows all objectives and design variables
fig = plot_parallel_coordinates(result)
fig.show()
# Customize what to display
fig = plot_parallel_coordinates(
result,
include_design_vars=True,
include_objectives=True,
include_constraints=False,
color_by="objective_0", # Color lines by first objective
highlight_feasible=True, # Highlight feasible solutions
title="Optimization Results - Parallel Coordinates"
)
fig.show()
# Highlight specific result sets
# This is useful after creating result sets from analysis
fig = plot_parallel_coordinates(
result,
result_sets=["pareto_front", "top_3_recommended"], # Show only these sets
color_by="Set", # Color by result set membership
title="Pareto Front and Top Solutions"
)
fig.show()
# Save to HTML for sharing
fig.write_html("parallel_coordinates.html")
Scatter Plot Matrix (SPLOM)¶
SPLOM shows all pairwise relationships between variables.
from optiscope.plotting import plot_scatter_matrix
# Auto-select variables (limited to avoid overcrowding)
fig = plot_scatter_matrix(result)
fig.show()
# Manually specify variables to include
fig = plot_scatter_matrix(
result,
variables=["design_var_0", "design_var_1", "objective_0", "objective_1"],
color_by="objective_0",
show_distributions=True, # Show histograms on diagonal
title="Scatter Matrix - Key Variables"
)
fig.show()
# Highlight result sets
fig = plot_scatter_matrix(
result,
variables=["objective_0", "objective_1", "objective_2"],
color_by="Set", # Color by result set
marker_by="Set", # Different markers for different sets
result_sets=["pareto_front", "filtered_pareto"],
title="Pareto Front Analysis"
)
fig.show()
Correlation Heatmap¶
Visualize correlations between all variables.
from optiscope.plotting import plot_correlation_heatmap
# Show correlations for all variables
fig = plot_correlation_heatmap(
result,
include_objectives=True,
include_design_vars=True,
include_constraints=False,
method="pearson", # or "spearman" for rank correlation
title="Variable Correlations"
)
fig.show()
# Focus on objectives only
fig = plot_correlation_heatmap(
result,
include_objectives=True,
include_design_vars=False,
include_constraints=False,
title="Objective Correlations"
)
fig.show()
Pareto Front Visualization¶
Specialized plots for 2D and 3D Pareto fronts.
from optiscope.plotting import plot_pareto_front_2d, plot_pareto_front_3d
# 2D Pareto front (for 2-objective problems)
fig_2d = plot_pareto_front_2d(
result,
obj_x=0, # First objective on x-axis
obj_y=1, # Second objective on y-axis
pareto_set="pareto_front", # Name of the Pareto result set
show_dominated=True, # Show dominated solutions in gray
show_ideal_nadir=True, # Show ideal and nadir points
title="Pareto Front - 2D View"
)
fig_2d.show()
# 3D Pareto front (for 3-objective problems)
fig_3d = plot_pareto_front_3d(
result,
obj_x=0,
obj_y=1,
obj_z=2,
pareto_set="pareto_front",
show_surface=True, # Render as a surface
title="Pareto Front - 3D View"
)
fig_3d.show()
# Compare filtered vs full Pareto front
fig_comparison = plot_pareto_front_2d(
result,
obj_x=0,
obj_y=1,
result_sets=["pareto_front", "filtered_pareto"],
color_by="Set",
title="Full vs Filtered Pareto Front"
)
fig_comparison.show()
Optimization History Plots¶
Visualize how objectives, variables, and constraints evolve over iterations.
from optiscope.plotting.time_series import (
plot_optimization_history,
plot_time_series,
plot_time_series_resampled
)
# Plot all optimization history (objectives, variables, constraints)
# This creates separate plots for each category
figs = plot_optimization_history(
result,
variables=None, # None means auto-select all
objectives=None,
constraints=None,
show_markers=True,
show_feasibility=True
)
# Show each figure
for category, fig in figs.items():
fig.show()
# Plot specific objectives over time
fig_objectives = plot_time_series(
result,
columns=["objective_0", "objective_1"],
data_attr="objectives",
title="Objective Evolution",
show_markers=True,
single_plot=True # Show all on one plot
)
fig_objectives.show()
# Plot design variables over time
fig_variables = plot_time_series(
result,
columns=["design_var_0", "design_var_1", "design_var_2"],
data_attr="design_vars",
title="Design Variable Evolution",
show_markers=False,
single_plot=False # Separate subplot for each variable
)
fig_variables.show()
Large Optimization History (Resampled)¶
For very large datasets (thousands of iterations), use the resampled version for better performance.
from optiscope.plotting.time_series import plot_time_series_resampled
# This requires plotly-resampler to be installed
# pip install plotly-resampler
# Plot large optimization history with automatic downsampling
fig_resampled = plot_time_series_resampled(
result,
columns=["objective_0", "objective_1", "objective_2"],
data_attr="objectives",
title="Objective Evolution (Resampled)",
show_markers=False, # Markers not recommended for large datasets
single_plot=False,
max_n_samples=1000 # Maximum points to show at any zoom level
)
# The plot will dynamically resample based on zoom level
fig_resampled.show()
# You can also use the resampled version for variables
fig_vars_resampled = plot_time_series_resampled(
result,
columns=None, # Auto-select all design variables
data_attr="design_vars",
title="Design Variables (Resampled)",
max_n_samples=500
)
fig_vars_resampled.show()
Complete Example Workflow¶
Here's a complete example combining data loading, analysis, and visualization:
from optiscope.io.csv_handler import CSVHandler
from optiscope.analysis import (
identify_pareto_front,
adaptive_smart_pareto_filter,
topsis
)
from optiscope.plotting import (
plot_parallel_coordinates,
plot_pareto_front_2d,
plot_scatter_matrix
)
from optiscope.core.result_set import ResultSet
import numpy as np
# 1. Load data
handler = CSVHandler()
result = handler.read("optimization_results.csv")
print(f"Loaded {len(result.objectives)} solutions")
# 2. Identify Pareto front
pareto_mask = identify_pareto_front(
objectives=result.objectives,
directions=result.metadata.optimization_directions
)
pareto_indices = np.where(pareto_mask)[0]
print(f"Found {len(pareto_indices)} Pareto-optimal solutions")
# 3. Filter to representative subset
filtered_indices = adaptive_smart_pareto_filter(
objectives=result.objectives[pareto_indices],
target_reduction=0.3,
min_points=10,
normalize=True
)
final_indices = pareto_indices[filtered_indices]
print(f"Reduced to {len(final_indices)} representative solutions")
# 4. Rank with TOPSIS
weights = [0.4, 0.3, 0.3] # Adjust based on your priorities
scores = topsis(
objectives=result.objectives[final_indices],
weights=weights,
directions=result.metadata.optimization_directions
)
best_idx = final_indices[np.argmax(scores)]
print(f"Best solution: index {best_idx}, score {scores.max():.3f}")
# 5. Create result sets
result.add_result_set(ResultSet(
name="pareto_front",
indices=pareto_indices.tolist(),
created_by="analysis",
description="All Pareto-optimal solutions"
))
result.add_result_set(ResultSet(
name="filtered_pareto",
indices=final_indices.tolist(),
created_by="smart_pareto_filter",
description="Representative Pareto subset"
))
result.add_result_set(ResultSet(
name="best_solution",
indices=[best_idx],
created_by="topsis",
description=f"Best solution (TOPSIS score: {scores.max():.3f})"
))
# 6. Visualize
# Parallel coordinates showing all result sets
fig_parallel = plot_parallel_coordinates(
result,
result_sets=["pareto_front", "filtered_pareto", "best_solution"],
color_by="Set",
title="Optimization Analysis Results"
)
fig_parallel.show()
# 2D Pareto front
fig_pareto = plot_pareto_front_2d(
result,
obj_x=0,
obj_y=1,
result_sets=["pareto_front", "filtered_pareto", "best_solution"],
color_by="Set",
title="Pareto Front Analysis"
)
fig_pareto.show()
# Scatter matrix of objectives
fig_splom = plot_scatter_matrix(
result,
variables=[f"objective_{i}" for i in range(len(result.objectives.columns))],
result_sets=["filtered_pareto", "best_solution"],
color_by="Set",
title="Objective Space Analysis"
)
fig_splom.show()
# 7. Save results
handler.write(result, "analyzed_results.csv")
print("Analysis complete! Results saved.")
Tips and Best Practices¶
When to Use Each Tool¶
- Pareto Front Identification: Always start here for multi-objective problems to identify the best trade-off solutions.
- Smart Pareto Filter: Use when your Pareto front has >50 solutions and you need a cleaner visualization or a manageable set for decision-making.
- TOPSIS: Use when you have clear preferences (weights) for objectives and need to select a single best solution.
- Parallel Coordinates: Best for exploring high-dimensional spaces and understanding variable relationships.
- SPLOM: Best for identifying correlations and patterns between specific variables.
- Time Series Plots: Essential for understanding convergence and optimization dynamics.
Performance Considerations¶
- For large datasets (>10,000 points), use
plot_time_series_resampledinstead ofplot_time_series. - When creating SPLOM, limit the number of variables to 5-7 for readability.
- Use
adaptive_smart_pareto_filterwith reasonablemax_pointsto keep visualizations clean.