Plotting the progress and results#
Introduction#
Every optimizer in nextnano optimizers records its run simulations
in the Simulation_*.log, Simulation_*.json and
Simulation_*.dat files. Using those files, you can visualize the progress of the optimization or
analyze the results afterwards.
The plotting is available for all optimizers, and the interface is the same for all of them.
In all the examples below, optimizer is an instance of
LocalOptimizer, BayesianOptimization or Evolution.
Note
The plotting functionality is optional and requires the additional dependency nextnano_optimizers[plot].
If you do not have it installed, the plotting methods will raise an error.
Watching the optimization in real time#
You can track the progress of optimization while it is running by passing
live_progress=True to run().
optimizer.run(
...,
live_progress=True,
)
This opens a separate window showing the objective values and input variables of the evaluated candidates. The figures update automatically as new evaluations are completed.
The window closes automatically when the run finishes.
Analyzing the live progress, one can judge whether the objective improves at all, or whether the search is stuck somewhere. In the latter case, it is advisable to stop the run and reconsider the optimization hyperparameters instead of waiting for the remaining evaluations.
Plotting the results after a run#
After completing an optimization, call plot_all() to generate figures from the recorded results:
optimizer.plot_all()
By default, the figures are saved in the figures subdirectory of the optimization output directory.
To display them in a window instead of saving them:
optimizer.plot_all(show=True, save_dir=False) # only show the figure in a window, do not save
You can also specify a directory where the figures are saved and the file format for the figures:
optimizer.plot_all(save_dir="path/to/the/folder", fig_format="pdf")
The available formats are "png", "svg" and "pdf".
Available plots#
Optimization progress#
The progress figure shows how the objective values and input variables of the evaluated designs change during the optimization.
It contains two groups of plots:
Objective values
Input variables
Each objective value and input varible has a separate plot on the progress figure. For example, the optimization with 2 objectives and 3 input variables will have 5 plots in total.
For LocalOptimizer and BayesianOptimization, each optimization step corresponds to one
design evaluation.
For Evolution, each optimization step contains \(n\) evaluations, where \(n\) is
a population size. Therefore the Evolution progress figures will have \(n\) points for each optimization step.
Final population figure for the Evolution#
For evolutionary algorithms, plot_all generates additional figures to show the final
population in both objective space and input space.
The input-variable figure shows the final population, with a separate plot for each pair of input variables.
For example, the evolution with 3 input variables well_width, barrier_width and doping will have 3 plots with pairs:
well_widthvs.barrier_widthwell_widthvs.dopingbarrier_widthvs.doping.
Each point represents one candidate, and the Pareto solutions of the final generation are highlighted.
The objectives figure follows the same convetion: each pair of objectives have a separate plot and the Pareto front is highlighted.
Customizing the plots#
You can customize the figures using setup_plotting.
The configuration applies to both the live_progress``figrue and figures generated by ``plot_all().
Axis labels#
By default, the plots use the input-variable names as input labels and generic label like objective or fitness for objectives. You can replace them with more descriptive labels and include physical units:
optimizer.setup_plotting(
param_names=[
"Well width (nm)",
"Barrier width (nm)",
"Alloy fraction",
],
fitness_names=["Energy error (eV)"],
)
The order of param_names must match variable_names in IO. Similarly,
fitness_names must contain one label for each objective returned by Metric.
Selecting the progress curves#
By default, the progress figure shows the evaluated candidates together with summary curves describing the optimization.
You can choose which curves to display using progress_series:
optimizer.setup_plotting(
progress_series=["candidates", "best"],
)
The two curves are:
candidates: Values of the evaluated candidates.best: Best objective value found so far.
For evolutionary optimization, additional curves are available (applies both to input variables and objective values):
mean: Mean value of the population.median: Median value of the population.min-max: Range between the minimum and maximum values in the population.
These curves help you understand how the population evolves, rather than focusing only on the best candidate.
For example:
optimizer.setup_plotting(
progress_series=["candidates", "mean", "best"],
)
The complete set of available curves is described in the API reference of the individual optimizers: LocalOptimizer, BayesianOptimization and Evolution.
Plotting a previous run#
The plotting methods described above are called through an optimizer object. You can also
create figures directly from a JSON log file. Every optimization writes a Simulation_*.json file containing the evaluated input
variables and their objective values.
To plot a previously completed run:
from nextnano_optimizers.plotting import OptimizationPlotter
plotter = OptimizationPlotter.from_json(
"Simulation_2026_10_19.json", # path to the json file
)
plotter.plot_all(show=True)
This is useful when you want to analyze an earlier optimization or regenerate figures with different settings.
Additional information#
See the individual API reference of every optimizer for the full set of plotting options: LocalOptimizer, BayesianOptimization and Evolution.
See nextnano_optimizers.plotting module for the
OptimizationPlotter API.