Skip to content

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:

  1. Start with Loading Data to understand how to get your optimization results into OptiScope
  2. Learn about Result Sets to organize your solutions
  3. Explore Analysis Examples to extract insights from your data
  4. Create Visualizations to understand and present your results
  5. 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_resampled instead of plot_time_series.
  • When creating SPLOM, limit the number of variables to 5-7 for readability.
  • Use adaptive_smart_pareto_filter with reasonable max_points to keep visualizations clean.

Saving and Sharing

# Save interactive HTML plots
fig.write_html("my_plot.html")

# Save static images
fig.write_image("my_plot.png", width=1200, height=800)

# Save results with result sets
handler.write(result, "results_with_sets.csv")