Skip to content

Parallel Coordinates

parallel_coordinates

Classes

Functions

plot_parallel_coordinates

plot_parallel_coordinates(results: OptimizationResult | list[OptimizationResult] | dict[str, OptimizationResult], selected_columns: list[str] | None = None, include_design_vars: bool = True, include_objectives: bool = True, include_constraints: bool = False, include_observables: bool = False, include_sets_as_dimensions: bool | list[str] = False, result_sets: list[str] | None = None, highlight_feasible: bool = False, constraint_tolerance: float = 1e-06, colorscale: str = 'Viridis', color_by: str | None = None, width: int = 1200, height: int = 700, title: str | None = None, theme: str | None = 'plotly_white', vertical: bool = False) -> Figure

Create a parallel coordinates plot from optimization results.

This unified function handles three use cases: 1. Single result with auto-selected columns (original plot_parallel_coordinates) 2. Multiple results with manual column selection (original plot_parallel_coordinates_from_results) 3. Multiple results comparison with common columns (original plot_parallel_coordinates_comparison)

Parameters:

Name Type Description Default
results OptimizationResult | list[OptimizationResult] | dict[str, OptimizationResult]

Single OptimizationResult, list of results, or dict mapping names to results

required
selected_columns list[str] | None

Specific columns to plot (overrides include_* flags if provided)

None
include_design_vars bool

Include design variables as axes

True
include_objectives bool

Include objectives as axes

True
include_constraints bool

Include constraints as axes

False
include_observables bool

Include observables as axes

False
include_sets_as_dimensions bool | list[str]

Include specific sets (or all if True) as boolean axes

False
result_sets list[str] | None

list of result set names to highlight with different colors

None
highlight_feasible bool

Color feasible vs infeasible solutions differently

False
constraint_tolerance float

Tolerance for constraint violations

1e-06
colorscale str

Plotly colorscale name

'Viridis'
color_by str | None

Column name or "_result" to color lines by

None
width int

Figure width

1200
height int

Figure height

700
title str | None

Plot title

None
theme str | None

Plotly theme to apply

'plotly_white'
vertical bool

If True, rotate plot to vertical orientation

False

Returns:

Type Description
Figure

Plotly Figure object

Source code in optiscope/plotting/parallel_coordinates.py
def plot_parallel_coordinates(
    results: OptimizationResult | list[OptimizationResult] | dict[str, OptimizationResult],
    selected_columns: list[str] | None = None,
    include_design_vars: bool = True,
    include_objectives: bool = True,
    include_constraints: bool = False,
    include_observables: bool = False,
    include_sets_as_dimensions: bool | list[str] = False,
    result_sets: list[str] | None = None,
    highlight_feasible: bool = False,
    constraint_tolerance: float = 1e-6,
    colorscale: str = "Viridis",
    color_by: str | None = None,
    width: int = 1200,
    height: int = 700,
    title: str | None = None,
    theme: str | None = "plotly_white",
    vertical: bool = False,
) -> go.Figure:
    """
    Create a parallel coordinates plot from optimization results.

    This unified function handles three use cases:
    1. Single result with auto-selected columns (original plot_parallel_coordinates)
    2. Multiple results with manual column selection (original plot_parallel_coordinates_from_results)
    3. Multiple results comparison with common columns (original plot_parallel_coordinates_comparison)

    Args:
        results: Single OptimizationResult, list of results, or dict mapping names to results
        selected_columns: Specific columns to plot (overrides include_* flags if provided)
        include_design_vars: Include design variables as axes
        include_objectives: Include objectives as axes
        include_constraints: Include constraints as axes
        include_observables: Include observables as axes
        include_sets_as_dimensions: Include specific sets (or all if True) as boolean axes
        result_sets: list of result set names to highlight with different colors
        highlight_feasible: Color feasible vs infeasible solutions differently
        constraint_tolerance: Tolerance for constraint violations
        colorscale: Plotly colorscale name
        color_by: Column name or "_result" to color lines by
        width: Figure width
        height: Figure height
        title: Plot title
        theme: Plotly theme to apply
        vertical: If True, rotate plot to vertical orientation

    Returns:
        Plotly Figure object
    """
    # Normalize inputs to list of (name, result) tuples
    if isinstance(results, OptimizationResult):
        results_list = [(results.problem_metadata.name, results)]
        is_comparison = False
    elif isinstance(results, dict):
        results_list = list(results.items())
        is_comparison = True
    elif isinstance(results, list):
        results_list = [(r.problem_metadata.name, r) for r in results]
        is_comparison = False
    else:
        raise ValueError("results must be OptimizationResult, list, or dict")

    if not results_list:
        return _create_error_figure("No results provided.")

    # Build dimensions based on mode
    if selected_columns:
        # Mode: Manual column selection (from_results style)
        dimensions, combined_df, result_keys = _build_dimensions_from_columns(
            results_list, selected_columns, include_sets_as_dimensions
        )
        if dimensions is None:
            return combined_df  # Actually an error figure in this case
    elif is_comparison:
        # Mode: Comparison with common columns
        dimensions, data_per_result = _build_comparison_dimensions(
            results_list, include_design_vars, include_objectives
        )
        if dimensions is None:
            return _create_error_figure("No common columns found across results")
        combined_df = None
    else:
        # Mode: Single result with auto-selected columns
        dimensions, data_dict = _build_dimensions_from_flags(
            results_list[0][1],
            include_design_vars,
            include_objectives,
            include_constraints,
            include_observables,
            include_sets_as_dimensions,
        )
        if not dimensions:
            return _create_error_figure("No data selected for parallel coordinates plot")
        combined_df = None

    # Create figure
    if is_comparison:
        fig = _create_comparison_traces(results_list, dimensions, data_per_result, vertical)
    else:
        # Determine coloring
        if selected_columns and combined_df is not None:
            line_dict = _get_color_dict_from_combined(
                combined_df, color_by, results_list, colorscale, vertical
            )
        else:
            result = results_list[0][1]
            line_dict = _get_color_dict_single(
                result,
                result_sets,
                highlight_feasible,
                constraint_tolerance,
                color_by,
                data_dict,
                colorscale,
                vertical,
            )

        # Add labelangle for vertical orientation
        parcoords_kwargs = {"line": line_dict, "dimensions": dimensions}
        if vertical:
            parcoords_kwargs["labelangle"] = -90

        fig = go.Figure(data=go.Parcoords(**parcoords_kwargs))

    # Set title
    if title:
        title_text = title
    elif is_comparison:
        title_text = "Parallel Coordinates Comparison"
    elif selected_columns:
        result_names = [name for name, _ in results_list]
        if len(result_names) > 1:
            title_text = f"Parallel Coordinates Plot (Results: {', '.join(result_names)})"
        else:
            title_text = "Parallel Coordinates Plot"
    else:
        title_text = f"Parallel Coordinates: {results_list[0][0]}"

    # Adjust margins for vertical orientation
    if vertical:
        margin_dict = dict(l=150, r=150, t=80, b=150)
    else:
        margin_dict = dict(l=100, r=100 if is_comparison else 50, t=80, b=50)

    # Update layout
    fig.update_layout(
        title=title_text,
        width=width,
        height=height,
        font=dict(size=11),
        margin=margin_dict,
        template=theme,
        showlegend=is_comparison,
    )

    return fig