Source code for pypesto.visualize.optimization_stats

from collections.abc import Iterable, Sequence

import matplotlib.axes
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import is_color_like

from pypesto.util import delete_nan_inf

from ..C import COLOR
from ..result import Result
from .clust_color import assign_colors, assign_colors_for_list
from .misc import process_result_list, process_start_indices


[docs] def optimization_run_properties_one_plot( results: Result, properties_to_plot: list[str] | None = None, size: tuple[float, float] = (18.5, 10.5), start_indices: int | Iterable[int] | None = None, colors: COLOR | list[COLOR] | np.ndarray | None = None, legends: str | list[str] | None = None, plot_type: str = "line", ) -> matplotlib.axes.Axes: """ Plot stats for allproperties specified in properties_to_plot on one plot. Parameters ---------- results: Optimization result obtained by 'optimize.py' or list of those properties_to_plot: Optimization run properties that should be plotted size: Figure size (width, height) in inches. Is only applied when no ax object is specified start_indices: List of integers specifying the multistarts to be plotted or int specifying up to which start index should be plotted colors: List of colors recognized by matplotlib colors (one color per property in properties_to_plot), or single color. If not set and one result, clustering is done and colors are assigned automatically legends: Labels, one label per optimization property plot_type: Specifies plot type. Possible values: 'line' and 'hist' Returns ------- ax: The plot axes. Examples -------- .. code-block:: python optimization_run_properties_one_plot( result1, properties_to_plot=['time'], colors=[.5, .9, .9, .3] ) optimization_run_properties_one_plot( result1, properties_to_plot=['time', 'n_grad'], colors=[[.5, .9, .9, .3], [.2, .1, .9, .5]] ) """ if properties_to_plot is None: properties_to_plot = [ "time", "n_fval", "n_grad", "n_hess", "n_res", "n_sres", ] if colors is None: colors = assign_colors_for_list(len(properties_to_plot)) elif is_color_like(colors): colors = [colors] if len(colors) != len(properties_to_plot): raise ValueError( "Number of colors should be the same as number " "of optimization properties to plot" ) if legends is None: legends = properties_to_plot elif not isinstance(legends, list): legends = [legends] if len(legends) != len(properties_to_plot): raise ValueError( "Number of legends should be the same as number of " "optimization properties to plot" ) ax = plt.subplots()[1] fig = plt.gcf() fig.set_size_inches(*size) for idx, prop_name in enumerate(properties_to_plot): optimization_run_property_per_multistart( results, prop_name, ax, size, start_indices, colors[idx], legends[idx], plot_type, ) ax.set_ylabel("property value") ax.set_title("Optimization properties per optimization run") return ax
[docs] def optimization_run_properties_per_multistart( results: Result | Sequence[Result], properties_to_plot: list[str] | None = None, size: tuple[float, float] = (18.5, 10.5), start_indices: int | Iterable[int] | None = None, colors: COLOR | list[COLOR] | np.ndarray | None = None, legends: str | list[str] | None = None, plot_type: str = "line", ) -> dict[str, plt.Subplot]: """ One plot per optimization property in properties_to_plot. Parameters ---------- results: Optimization result obtained by 'optimize.py' or list of those properties_to_plot: Optimization run properties that should be plotted size: Figure size (width, height) in inches. Is only applied when no ax object is specified start_indices: List of integers specifying the multistarts to be plotted or int specifying up to which start index should be plotted colors: List of colors recognized by matplotlib (one color per result in results), or single color. If not set and one result, clustering is done and colors are assigned automatically legends: Labels for line plots, one label per result object plot_type: Specifies plot type. Possible values: 'line' and 'hist' Returns ------- ax: The plot axes. Examples -------- .. code-block:: python optimization_run_properties_per_multistart( result1, properties_to_plot=['time'], colors=[.5, .9, .9, .3] ) optimization_run_properties_per_multistart( [result1, result2], properties_to_plot=['time'], colors=[[.5, .9, .9, .3], [.2, .1, .9, .5]] ) optimization_run_properties_per_multistart( result1, properties_to_plot=['time', 'n_grad'], colors=[.5, .9, .9, .3] ) optimization_run_properties_per_multistart( [result1, result2], properties_to_plot=['time', 'n_fval'], colors=[[.5, .9, .9, .3], [.2, .1, .9, .5]] ) """ if properties_to_plot is None: properties_to_plot = [ "time", "n_fval", "n_grad", "n_hess", "n_res", "n_sres", ] num_subplot = len(properties_to_plot) # compute, how many rows and columns we need for the subplots num_row = int(np.round(np.sqrt(num_subplot))) num_col = int(np.ceil(num_subplot / num_row)) fig, axes = plt.subplots(num_row, num_col, squeeze=False) fig.set_size_inches(*size) for ax in axes.flat[num_subplot:]: ax.remove() axes = dict(zip(range(num_subplot), axes.flat, strict=True)) for idx, prop_name in enumerate(properties_to_plot): ax = axes[idx] optimization_run_property_per_multistart( results, prop_name, ax, size, start_indices, colors, legends, plot_type, ) return axes
[docs] def optimization_run_property_per_multistart( results: Result | Sequence[Result], opt_run_property: str, axes: matplotlib.axes.Axes | None = None, size: tuple[float, float] = (18.5, 10.5), start_indices: int | Iterable[int] | None = None, colors: COLOR | list[COLOR] | np.ndarray | None = None, legends: str | list[str] | None = None, plot_type: str = "line", ) -> matplotlib.axes.Axes: """ Plot stats for an optimization run property specified by opt_run_property. It is possible to plot a histogram or a line plot. In a line plot, on the x-axis are the numbers of the multistarts, where the multistarts are ordered with respect to a function value. On the y-axis of the line plot the value of the corresponding parameter for each multistart is displayed. Parameters ---------- opt_run_property: optimization run property to plot. One of the 'time', 'n_fval', 'n_grad', 'n_hess', 'n_res', 'n_sres' results: Optimization result obtained by 'optimize.py' or list of those axes: Axes object to use size: Figure size (width, height) in inches. Is only applied when no ax object is specified start_indices: List of integers specifying the multistarts to be plotted or int specifying up to which start index should be plotted colors: List of colors recognized by matplotlib (one color per result in results), or single color. If not set and one result, clustering is done and colors are assigned automatically legends: Labels for line plots, one label per result object plot_type: Specifies plot type. Possible values: 'line', 'hist', 'both' Returns ------- axes: The plot axes. """ supported_properties = { "time": "Wall-clock time (seconds)", "n_fval": "Number of function evaluations", "n_grad": "Number of gradient evaluations", "n_hess": "Number of Hessian evaluations", "n_res": "Number of residuals evaluations", "n_sres": "Number of residual sensitivity evaluations", } if opt_run_property not in supported_properties: raise ValueError( "Wrong value of opt_run_property. Only the following " "values are allowed: 'time', 'n_fval', 'n_grad', " "'n_hess', 'n_res', 'n_sres'" ) # parse input (results, colors, legends) = process_result_list(results, colors, legends) # axes if axes is None: ncols = 2 if plot_type == "both" else 1 fig, axes = plt.subplots(1, ncols) fig.set_size_inches(*size) fig.suptitle( f"{supported_properties[opt_run_property]} per optimizer run" ) else: axes.set_title( f"{supported_properties[opt_run_property]} per optimizer run" ) # loop over results for j, result in enumerate(results): if plot_type == "both": axes[0] = stats_lowlevel( result, opt_run_property, supported_properties[opt_run_property], axes[0], start_indices, colors[j], legends[j], ) axes[1] = stats_lowlevel( result, opt_run_property, supported_properties[opt_run_property], axes[1], start_indices, colors[j], legends[j], plot_type="hist", ) else: axes = stats_lowlevel( result, opt_run_property, supported_properties[opt_run_property], axes, start_indices, colors[j], legends[j], plot_type, ) if sum(legend is not None for legend in legends) > 0: if plot_type == "both": for ax in axes: ax.legend() else: axes.legend() return axes
def stats_lowlevel( result: Result, property_name: str, axis_label: str, ax: matplotlib.axes.Axes, start_indices: int | Iterable[int] | None = None, color: COLOR | list[COLOR] | np.ndarray | None = "C0", legend: str | None = None, plot_type: str = "line", ): """ Plot values of the optimization run property across different multistarts. Parameters ---------- result: Optimization result obtained by 'optimize.py' property_name: name of the optimization result property which value should be plotted axis_label: Label for the y-axis of the line plot or x-axis of the histogram ax: Axes object to use start_indices: List of integers specifying the multistarts to be plotted or int specifying up to which start index should be plotted color: List of colors recognized by matplotlib (length equal to the number of multistarts), or single color If not set, then for the line plot clustering is done and colors are assigned automatically legend: Label describing the result plot_type: Specifies plot type. Possible values: 'line' and 'hist' Returns ------- ax: The plot axes. """ fvals = result.optimize_result.fval values = [[res[property_name]] for res in result.optimize_result.list] values, fvals = delete_nan_inf(fvals, values) if start_indices is not None: start_indices = process_start_indices(result, start_indices) values = values[start_indices] fvals = fvals[start_indices] n_starts = len(values) # assign colors colors = assign_colors(vals=fvals, colors=color, balance_alpha=False) sorted_indices = sorted(range(n_starts), key=lambda j: fvals[j]) values = values[sorted_indices] if plot_type == "line": # plot line ax.plot(range(n_starts), values, color=[0.7, 0.7, 0.7, 0.6]) # plot points for i, v in enumerate(values): if i == 0: tmp_legend = legend else: tmp_legend = None ax.scatter(i, v, color=colors[i], marker="o", label=tmp_legend) ax.set_xlabel("Ordered optimizer run") ax.set_ylabel(axis_label) else: ax.hist(values, color=color, bins="auto", label=legend) ax.set_xlabel(axis_label) ax.set_ylabel("Number of multistarts") return ax