OptimizationPlotter#

class nextnano_optimizers.plotting.OptimizationPlotter(data: dict, param_names: list | None = None, fitness_names: list | None = None, exclude_failed: bool = False, fitness_limits: list | dict | None = None, progress_series: list | str | None = None, series_labels: dict | None = None, series_specs: dict | None = None, iteration_label: str | None = None, progress_title: str | None = None, population_label: str | None = None)#

Bases: object

Visualizes the outcome of an optimization run from its JSON log.

An optimizer opts into plotting by writing the log schema; the plotter never asks which optimizer produced a log. Every plot_* method returns the matplotlib Figure (and accepts style kwargs), so results can be further composed or restyled by the caller. The iteration wording is neutral by default; each optimizer names its own through setup_plotting.

Parameters:
datadict

Parsed JSON log, i.e. {"simulation": {"gen1": [...], ...}, "summary": {...}} as an optimizer’s run() writes it.

param_names, fitness_nameslist of str, optional

Axis labels for the input variables / objectives. Default to param1..N / fitness1..M.

exclude_failedbool, optional

Drop evaluations where every fitness component equals summary["non_execution_penalty"] (failed simulations) before plotting. Default False: opt-in, because it is only a heuristic – a genuine solution whose fitness happens to equal the penalty would be dropped too. Enable it when penalty outliers flatten the axes.

fitness_limitslist or dict, optional

Per-objective (min, max) bounds; a solution whose fitness falls outside any given bound is discarded from every plot (objective, parameter, objective-space and input-space panels alike), so all panels keep showing the same population. Either a list with one entry per objective (None entries mean “no limit on this objective”) or a sparse dict keyed by objective name or index:

fitness_limits=[(0, 100), None]
fitness_limits={"fitness2": (None, 1e3)}

None inside a pair leaves that side unbounded. A NaN fitness in a limited objective is discarded too (NaN never satisfies a bound). Note the Pareto highlights come from the run summary and are not filtered, so a tight limit can leave a highlighted point outside the surviving scatter.

progress_seriessequence of str or str, optional

Default selection of per-panel curves for plot_progress(), any of PROGRESS_SERIES (pass "all" for every curve). None (default) draws DEFAULT_SERIES. A series argument to plot_progress() (or progress_series to plot_all()) overrides it per call.

series_labelsdict, optional

Legend text per curve, keyed by curve name, e.g. {"candidates": "samples"}. A curve not listed keeps its own name. The name is still what selects a curve in progress_series, on the --series flag and in PROGRESS_SERIES; only the legend changes.

series_specsdict, optional

Per-curve drawing overrides, keyed by curve name, each holding kind ("scatter", "line" or "band") and/or style:

series_specs={"candidates": {"kind": "line", "style": {"marker": "o"}}}

A style given replaces the curve’s own rather than patching it, and falls back to the table’s only while kind is unchanged: style keywords belong to the drawing primitive, so a curve redrawn as something else starts from nothing. What a curve shows is unaffected – the evaluations stay the evaluations, drawn differently.

iteration_labelstr, optional

What one optimization step is called in the figures (progress x-axis and final-population legend). None (default) uses the facade’s own word, "iteration".

progress_titlestr, optional

Suptitle of the progress figure. None (default) uses the facade’s own: "Optimization progress" here.

population_labelstr, optional

What the final iteration’s points are called in the objective- and input-space figures, both in the legend and in the title. None (default) uses the facade’s own: "final population candidates".

Attributes:
runRunData

The parsed run: dimensions (n_params, n_obj), resolved axis labels (param_names, fitness_names), excluded-evaluation counts (n_failed, n_limited) and the summary dict.

classmethod from_arrays(generation, params, fits, *, summary=None, param_names=None, fitness_names=None, exclude_failed=False, fitness_limits=None, progress_series=None, series_labels=None, series_specs=None, iteration_label=None, progress_title=None, population_label=None) → OptimizationPlotter#

Build a plotter straight from in-memory per-evaluation arrays.

Bypasses the JSON log entirely – used for live plotting during a run, where the accumulated generation/params/fits are already in memory.

Parameters:
generationarray-like of int, shape (n,)

Iteration index of each evaluated individual.

paramsarray-like, shape (n, n_params)

Input-variable values of each evaluated individual.

fitsarray-like, shape (n, n_obj)

Fitness values of each evaluated individual.

summarydict, optional

Summary dict; only non_execution_penalty matters for the progress plot (failed-evaluation masking).

fitness_limitslist or dict, optional

Per-objective (min, max) row filter; see the class docstring.

classmethod from_json(json_path, **kwargs) → OptimizationPlotter#

Build a plotter from a JSON log file on disk (offline use).

classmethod from_manager(manager, **kwargs) → OptimizationPlotter#

Build a plotter from a finished run’s optimization manager.

Reads the run’s JSON log directly from the manager’s logger, so no log path is needed. The manager’s non_execution_penalty fills that summary key when the log omitted it, so failed-evaluation masking works even on a summary written without it.

classmethod from_optimizer(optimizer, **kwargs) → OptimizationPlotter#

Build a plotter from a finished optimizer, whichever one it is.

Finds the run’s JSON log through the optimizer’s manager, so a caller holding a finished Evolution, LocalOptimizer or BayesianOptimization needs no log path. The figures are worded neutrally unless the caller says otherwise: a log does not record which optimizer wrote it, so the plotter cannot tell, and optimizer.plot_all() is the route that knows.

Parameters:
optimizerEvolution or LocalOptimizer or BayesianOptimization

An optimizer whose run has produced a log.

**kwargs

Forwarded to the constructor, as from_json() forwards them.

Returns:
OptimizationPlotter

A plotter over that run’s log.

plot_all(save_dir=None, show=False, progress_series=None, fig_format='png')#

Produce all available figures (progress, objective space, input space).

Parameters:
save_dirstr, default=None

Directory to save the figures into, created if it does not exist. They are named after what they show – progress.<ext>, pareto.<ext>, inputs.<ext>, where <ext> is fig_format – so two runs saved into one directory overwrite each other. None (default) does not save them.

showbool, optional

Call plt.show() at the end. Default False (never blocks in library code).

progress_seriessequence of str or str, optional

Which per-panel curves the progress figure draws, forwarded to plot_progress() (see its series argument; pass "all" for every curve). None (default) falls back to the plotter’s progress_series.

fig_formatstr, optional

File format the saved figures are written in, e.g. "png" (default), "pdf", "svg", "jpg". Any format the active matplotlib backend supports is accepted; a leading dot is optional and case is ignored. Ignored when save_dir is None.

Raises:
ValueError

If fig_format is not a format the active matplotlib backend can write.

plot_inputs()#

Final population in input (decision-variable) space, Pareto highlighted.

Input-space counterpart of plot_pareto. Returns None for a single parameter – an input-space view needs at least two parameters to form a pair, and parameter-vs-iteration is already covered by plot_progress. For >= 2 parameters it draws a scatter for every pair of parameters: the final population’s values as points, with the final-generation Pareto solutions highlighted.

plot_pareto()#

Final population in objective space, Pareto front highlighted.

Returns None for a single objective – an objective-space view needs at least two objectives, and fitness-vs-iteration is already covered by plot_progress. For >= 2 objectives it draws a scatter for every pair of objectives: the final population’s fitnesses as points, with the Pareto-front points highlighted; for exactly 2 objectives the Pareto points are connected into the front line.

plot_progress(fig=None, series=None)#

Per-iteration progress of objectives and parameters.

Returns the Figure, laid out in two columns sharing the iteration x-axis: objectives on the left, parameters on the right. Empty cells (when the objective and parameter counts differ) are hidden. When any evaluations are excluded (exclude_failed / fitness_limits), an extra panel directly below the objective panels charts the per-iteration excluded counts, one line per reason (failed / out-of-limit).

Parameters:
seriessequence of str, optional

Which per-panel curves to draw, any of PROGRESS_SERIES (candidates, min-max, min, max, median, mean, best), or "all" for every one of them. None (default) falls back to the plotter’s progress_series, which itself defaults to DEFAULT_SERIES (candidates, min-max, mean, best); min, max and median are available but off by default. Pass an explicit list to override, e.g. series=["median", "min", "max"]. best (the best-so-far, i.e. the running minimum over iterations) is only drawn on the objective panels.

If ``fig`` is given, it is cleared and reused instead of creating a new
figure – this lets a live view redraw into the same window (far cheaper
than tearing down and recreating the figure every iteration).
classmethod validate_config(*, expected_n_params=None, expected_n_obj=None, **kwargs)#

Validate plotting keyword arguments without building a plotter.

Lets a caller that configures plotting ahead of time (notably nextnano_optimizers.optimizer.Evolution.setup_plotting()) reject a bad kwarg at the point it was passed, rather than much later when the figures are drawn – or silently, in the detached live-viewer process whose stderr is discarded. Needs no data and no matplotlib.

Parameters:
expected_n_params, expected_n_objint, optional

Problem dimensions to check the lengths of param_names / fitness_names against. Leave None (default) when unknown, and that length check is skipped.

**kwargs

The candidate plotting kwargs (the same ones __init__ accepts).

Raises:
TypeError

If kwargs holds a name that is not a plotter kwarg.

ValueError

If progress_series names an unknown curve, or param_names / fitness_names has a length other than the expected dimension.