Skip to content

Scatter Matrix

scatter_matrix

Scatter Plot Matrix (SPLOM) for optimization visualization.

Provides interactive scatter matrix showing all pairwise relationships between variables with: - Brushing and linking across all subplots - Distribution plots on diagonal - Feasibility highlighting - Result set coloring - Correlation analysis

Classes

Functions

plot_scatter_matrix

plot_scatter_matrix(result: OptimizationResult, variables: list[str] | None = None, include_objectives: bool = True, include_design_vars: bool = True, max_vars: int = 8, color_by: str | None = None, result_sets: list[str] | None = None, highlight_feasible: bool = False, show_distributions: bool = True, show_correlations: bool = True, constraint_tolerance: float = 1e-06, marker_size: int = 4, width: int = 1000, height: int = 1000, title: str | None = None) -> Figure

Create an interactive scatter plot matrix (SPLOM).

Parameters:

Name Type Description Default
result OptimizationResult

OptimizationResult object

required
variables list[str] | None

Specific variable names to include (if None, auto-select)

None
include_objectives bool

Include objectives in matrix

True
include_design_vars bool

Include design variables in matrix

True
max_vars int

Maximum number of variables to include

8
color_by str | None

Variable name to color points by

None
result_sets list[str] | None

List of result set names for coloring

None
highlight_feasible bool

Color by feasibility

False
show_distributions bool

Show histograms/KDE on diagonal

True
show_correlations bool

Show correlation values in upper triangle

True
constraint_tolerance float

Tolerance for feasibility check

1e-06
marker_size int

Size of markers

4
width int

Figure width in pixels

1000
height int

Figure height in pixels

1000
title str | None

Plot title

None

Returns:

Type Description
Figure

Plotly Figure with interactive scatter matrix

Source code in optiscope/plotting/scatter_matrix.py
def plot_scatter_matrix(
    result: OptimizationResult,
    variables: list[str] | None = None,
    include_objectives: bool = True,
    include_design_vars: bool = True,
    max_vars: int = 8,
    color_by: str | None = None,
    result_sets: list[str] | None = None,
    highlight_feasible: bool = False,
    show_distributions: bool = True,
    show_correlations: bool = True,
    constraint_tolerance: float = 1e-6,
    marker_size: int = 4,
    width: int = 1000,
    height: int = 1000,
    title: str | None = None,
) -> go.Figure:
    """
    Create an interactive scatter plot matrix (SPLOM).

    Args:
        result: OptimizationResult object
        variables: Specific variable names to include (if None, auto-select)
        include_objectives: Include objectives in matrix
        include_design_vars: Include design variables in matrix
        max_vars: Maximum number of variables to include
        color_by: Variable name to color points by
        result_sets: List of result set names for coloring
        highlight_feasible: Color by feasibility
        show_distributions: Show histograms/KDE on diagonal
        show_correlations: Show correlation values in upper triangle
        constraint_tolerance: Tolerance for feasibility check
        marker_size: Size of markers
        width: Figure width in pixels
        height: Figure height in pixels
        title: Plot title

    Returns:
        Plotly Figure with interactive scatter matrix
    """
    # Select variables to include
    var_names, var_data = _select_variables(
        result, variables, include_objectives, include_design_vars, max_vars
    )

    if len(var_names) < 2:
        raise ValueError("Need at least 2 variables for scatter matrix")

    n_vars = len(var_names)

    # Prepare color data
    color_data, color_label, colorscale, colorbar_params = _prepare_color_data(
        result, color_by, result_sets, highlight_feasible, constraint_tolerance
    )

    # Create subplots
    fig = make_subplots(
        rows=n_vars,
        cols=n_vars,
        horizontal_spacing=0.02,
        vertical_spacing=0.02,
        # subplot_titles=var_names if n_vars <= 6 else None,
    )

    # Calculate correlations if requested
    correlations = None
    if show_correlations:
        correlations = pd.DataFrame(var_data, columns=var_names).corr()

    # Check size of data to plot to avoid performance issues
    max_points = 5000
    if var_data.shape[0] > max_points:
        # use scattergl for large datasets
        scatter_function = go.Scattergl
    else:
        scatter_function = go.Scatter

    # Add scatter plots and distributions
    for i in range(n_vars):
        for j in range(n_vars):
            row, col = i + 1, j + 1

            if i == j and show_distributions:
                # Diagonal: distribution plot
                _add_distribution_plot(
                    fig, var_data[:, i], var_names[i], color_data, colorscale, row, col
                )
            elif i < j and show_correlations:
                # Upper triangle: correlation values
                corr_val = correlations.iloc[i, j] if correlations is not None else 0.0
                _add_correlation_subplot(fig, corr_val, row, col)
            else:
                # Lower triangle and (if no correlation) upper: scatter plots
                if not (i < j and show_correlations):
                    # Prepare marker dict
                    marker_dict = dict(
                        size=marker_size,
                        color=color_data,
                        colorscale=colorscale,
                        showscale=(i == 0 and j == n_vars - 1),
                        opacity=0.6,
                    )

                    # Add colorbar config if this is the plot showing the scale
                    if i == 0 and j == n_vars - 1:
                        cbar = dict(title=color_label, x=1.02, len=0.3, y=0.85)
                        if colorbar_params:
                            cbar.update(colorbar_params)
                        marker_dict["colorbar"] = cbar

                    fig.add_trace(
                        scatter_function(
                            x=var_data[:, j],
                            y=var_data[:, i],
                            mode="markers",
                            marker=marker_dict,
                            showlegend=False,
                            hovertemplate=(
                                f"<b>{var_names[j]}</b>: %{{x:.4f}}<br>"
                                f"<b>{var_names[i]}</b>: %{{y:.4f}}<br>"
                                "<extra></extra>"
                            ),
                        ),
                        row=row,
                        col=col,
                    )

            # Update axes
            fig.update_xaxes(
                title_text=var_names[j] if i == n_vars - 1 else "",
                showticklabels=(i == n_vars - 1),
                showgrid=True,
                gridcolor="lightgray",
                row=row,
                col=col,
            )
            fig.update_yaxes(
                title_text=var_names[i] if j == 0 else "",
                showticklabels=(j == 0),
                showgrid=True,
                gridcolor="lightgray",
                row=row,
                col=col,
            )

    # Update layout
    title_text = title or f"Scatter Matrix: {result.problem_metadata.name}"

    fig.update_layout(
        title=dict(text=title_text, x=0.5, xanchor="center"),
        width=width,
        height=height,
        hovermode="closest",
        showlegend=False,
        plot_bgcolor="white",
    )

    return fig

plot_correlation_heatmap

plot_correlation_heatmap(result: OptimizationResult, variables: list[str] | None = None, include_objectives: bool = True, include_design_vars: bool = True, include_observables: bool = False, method: str = 'pearson', width: int = 800, height: int = 700, title: str | None = None) -> Figure

Create correlation heatmap for optimization variables.

Parameters:

Name Type Description Default
result OptimizationResult

OptimizationResult object

required
variables list[str] | None

Specific variables to include

None
include_objectives bool

Include objectives

True
include_design_vars bool

Include design variables

True
include_observables bool

Include observables

False
method str

Correlation method ('pearson', 'spearman', 'kendall')

'pearson'
width int

Figure width

800
height int

Figure height

700
title str | None

Plot title

None

Returns:

Type Description
Figure

Plotly Figure with correlation heatmap

Source code in optiscope/plotting/scatter_matrix.py
def plot_correlation_heatmap(
    result: OptimizationResult,
    variables: list[str] | None = None,
    include_objectives: bool = True,
    include_design_vars: bool = True,
    include_observables: bool = False,
    method: str = "pearson",
    width: int = 800,
    height: int = 700,
    title: str | None = None,
) -> go.Figure:
    """
    Create correlation heatmap for optimization variables.

    Args:
        result: OptimizationResult object
        variables: Specific variables to include
        include_objectives: Include objectives
        include_design_vars: Include design variables
        include_observables: Include observables
        method: Correlation method ('pearson', 'spearman', 'kendall')
        width: Figure width
        height: Figure height
        title: Plot title

    Returns:
        Plotly Figure with correlation heatmap
    """
    # Collect data
    data_dict = {}

    if variables:
        for var in variables:
            if not result.objectives.empty and var in result.objectives.columns:
                data_dict[var] = result.objectives[var].values
            elif not result.design_variables.empty and var in result.design_variables.columns:
                data_dict[var] = result.design_variables[var].values
            elif not result.observables.empty and var in result.observables.columns:
                data_dict[var] = result.observables[var].values
    else:
        if include_objectives and not result.objectives.empty:
            for col in result.objectives.columns:
                data_dict[col] = result.objectives[col].values

        if include_design_vars and not result.design_variables.empty:
            for col in result.design_variables.columns:
                data_dict[col] = result.design_variables[col].values

        if include_observables and not result.observables.empty:
            for col in result.observables.columns:
                data_dict[col] = result.observables[col].values

    if not data_dict:
        raise ValueError("No variables selected for correlation analysis")

    # Create DataFrame and calculate correlation
    df = pd.DataFrame(data_dict)

    if method == "pearson":
        corr_matrix = df.corr(method="pearson")
    elif method == "spearman":
        corr_matrix = df.corr(method="spearman")
    elif method == "kendall":
        corr_matrix = df.corr(method="kendall")
    else:
        raise ValueError(f"Unknown correlation method: {method}")

    # Create heatmap
    fig = go.Figure(
        data=go.Heatmap(
            z=corr_matrix.values,
            x=corr_matrix.columns,
            y=corr_matrix.index,
            colorscale="RdBu",
            zmid=0,
            zmin=-1,
            zmax=1,
            text=np.around(corr_matrix.values, decimals=2),
            texttemplate="%{text}",
            textfont={"size": 10},
            colorbar=dict(title="Correlation"),
            hovertemplate="<b>%{x}</b> vs <b>%{y}</b><br>Correlation: %{z:.3f}<extra></extra>",
        )
    )

    # Update layout
    title_text = (
        title or f"Correlation Matrix ({method.capitalize()}): {result.problem_metadata.name}"
    )

    fig.update_layout(
        title=title_text,
        xaxis=dict(side="bottom", tickangle=-45),
        yaxis=dict(side="left"),
        width=width,
        height=height,
        template="plotly_white",
    )

    return fig