Source code for pybop.plotting.plot_cost2d

import numpy as np


[docs] def plot_cost2d(cost, bounds=None, optim=None, steps=10): """ Plot a 2D visualization of a cost landscape using Plotly. This function generates a contour plot representing the cost landscape for a provided callable cost function over a grid of parameter values within the specified bounds. Parameters ---------- cost : callable The cost function to be evaluated. Must accept a list of parameters and return a cost value. bounds : numpy.ndarray, optional A 2x2 array specifying the [min, max] bounds for each parameter. If None, uses `get_param_bounds`. optim : object, optional An optimiser instance which, if provided, overlays its specific trace on the plot. steps : int, optional The number of intervals to divide the parameter space into along each dimension (default is 10). Returns ------- plotly.graph_objs.Figure The Plotly figure object containing the cost landscape plot. Raises ------ ValueError If the cost function does not return a valid cost when called with a parameter list. """ if bounds is None: # Set up parameter bounds bounds = get_param_bounds(cost) else: bounds = bounds # Generate grid x = np.linspace(bounds[0, 0], bounds[0, 1], steps) y = np.linspace(bounds[1, 0], bounds[1, 1], steps) # Initialize cost matrix costs = np.zeros((len(y), len(x))) # Populate cost matrix for i, xi in enumerate(x): for j, yj in enumerate(y): costs[j, i] = cost([xi, yj]) # Create figure fig = create_figure(x, y, costs, bounds, cost.problem.parameters, optim) # Display figure fig.show() return fig
[docs] def get_param_bounds(cost): """ Retrieve parameter bounds from a cost function's associated problem parameters. Parameters ---------- cost : callable The cost function with an associated 'problem' attribute containing 'parameters'. Returns ------- numpy.ndarray An array of shape (n_parameters, 2) containing the bounds for each parameter. """ bounds = np.empty((len(cost.problem.parameters), 2)) for i, param in enumerate(cost.problem.parameters): bounds[i] = param.bounds return bounds
[docs] def create_figure(x, y, z, bounds, params, optim): """ Create a Plotly figure with a 2D contour plot of the cost landscape. Parameters ---------- x : numpy.ndarray 1D array of x-coordinates for the meshgrid. y : numpy.ndarray 1D array of y-coordinates for the meshgrid. z : numpy.ndarray 2D array of cost function values corresponding to the meshgrid. bounds : numpy.ndarray A 2x2 array specifying the [min, max] bounds for each parameter. params : iterable An iterable of parameter objects with 'name' attributes for axis labeling. optim : object An optimiser instance with 'log' and 'x0' attributes for plotting traces. Returns ------- plotly.graph_objs.Figure The Plotly figure object with the contour plot and optimization traces. """ # Import plotly only when needed import plotly.graph_objects as go fig = go.Figure(data=[go.Contour(x=x, y=y, z=z)]) if optim is not None: optim_trace = np.array([item for sublist in optim.log for item in sublist]) optim_trace = optim_trace.reshape(-1, 2) # Plot initial guess fig.add_trace( go.Scatter( x=[optim.x0[0]], y=[optim.x0[1]], mode="markers", marker_symbol="x", marker=dict( color="red", line_color="midnightblue", line_width=1, size=12, showscale=False, ), showlegend=False, ) ) # Plot optimisation trace fig.add_trace( go.Scatter( x=optim_trace[:, 0], y=optim_trace[:, 1], mode="markers", marker=dict( color=[i / len(optim_trace) for i in range(len(optim_trace))], colorscale="YlOrBr", showscale=False, ), showlegend=False, ) ) # Set figure properties fig.update_layout( title="Cost Landscape", title_x=0.5, title_y=0.9, xaxis_title=params[0].name, yaxis_title=params[1].name, width=600, height=600, xaxis=dict(range=bounds[0]), yaxis=dict(range=bounds[1]), ) return fig