diff --git a/boa/__init__.py b/boa/__init__.py index 0803efc..647f757 100644 --- a/boa/__init__.py +++ b/boa/__init__.py @@ -15,7 +15,14 @@ from boa.metrics.metrics import * # noqa from boa.metrics.modular_metric import * # noqa from boa.metrics.synthetic_funcs import * # noqa -from boa.plotting import * # noqa +from boa.plotting import ( # noqa + app_view, + plot_contours, + plot_metrics_trace, + plot_pareto_frontier, + plot_slice, + scheduler_to_df, +) from boa.registry import _add_common_encodes_and_decodes from boa.runner import * # noqa from boa.scheduler import * # noqa diff --git a/boa/plot.py b/boa/plot.py new file mode 100644 index 0000000..467967e --- /dev/null +++ b/boa/plot.py @@ -0,0 +1,35 @@ +""" +BOA plotting CLI module + +You can launch a basic EDA plot view +of your optimization with:: + + python -m boa.plot path/to/scheduler.json + + +""" + + +import pathlib + +import click +import panel as pn + +from boa.plotting import app_view + + +@click.command() +@click.option( + "-sp", + "--scheduler-path", + type=click.Path(), + default="", + help="Path to scheduler json file.", +) +def main(scheduler_path): + template = app_view(scheduler=scheduler_path) + pn.serve({pathlib.Path(__file__).name: template}) + + +if __name__ == "__main__": + main() diff --git a/boa/plotting.py b/boa/plotting.py index f30cdf1..8c3eb02 100644 --- a/boa/plotting.py +++ b/boa/plotting.py @@ -393,3 +393,35 @@ def plot_pareto_frontier( fig = go.Figure(data=traces, layout=layout) return pn.pane.Plotly(fig) + + +def app_view( + scheduler: SchedulerOrPath, + metric_names: list[str] | None = None, +): + """Creates a web view of a variety of EDA plots from a scheduler. + + Parameters + ---------- + scheduler + Initialized scheduler or path to `scheduler.json file`. + metric_names + metric name or list of metric names to restrict dropdowns to. If None, will use all metric names. + """ + scheduler = _maybe_load_scheduler(scheduler) + view = pn.Column() + if scheduler.experiment.is_moo_problem: + pareto = plot_pareto_frontier(scheduler=scheduler, metric_names=metric_names) + else: + pareto = None + view.append(pn.Row(plot_metrics_trace(schedulers=scheduler, metric_names=metric_names), pareto)) + view.append(plot_slice(scheduler=scheduler)) + view.append(plot_contours(scheduler=scheduler, metric_names=metric_names)) + view.append(scheduler_to_df(scheduler)) + + template = pn.template.BootstrapTemplate( + site="BOA", + main=[view], + ) + + return template.servable() diff --git a/boa/storage.py b/boa/storage.py index bbc703a..0044853 100644 --- a/boa/storage.py +++ b/boa/storage.py @@ -246,6 +246,7 @@ def exp_opt_to_csv(experiment, opt_path: PathLike = "optimization.csv", dir_: Pa opt_path = pathlib.Path(dir_) / opt_path df = exp_to_df(experiment) df.to_csv(path_or_buf=opt_path, index=False, **kwargs) + logger.info(f"Saved optimization parametrization and objective to `{opt_path}`.") def scheduler_opt_to_csv(scheduler, **kwargs): diff --git a/docs/conf.py b/docs/conf.py index 1e6a06f..bfa0feb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -80,9 +80,10 @@ "example_optimization_results.ipynb", # "1moo_optimization_run.ipynb", # "1optimization_run.ipynb", - # "1run_r_streamlined.ipynb" + # "1run_r_streamlined.ipynb", # "2load_scheduler.ipynb", - # "2load_moo_scheduler.ipynb" + # "2load_moo_scheduler.ipynb", + # "2EDA_from_r_run.ipynb" ] nb_execution_timeout = 600 nb_execution_raise_on_error = True diff --git a/docs/examples/2EDA_from_r_run.ipynb b/docs/examples/2EDA_from_r_run.ipynb new file mode 100644 index 0000000..16d146d --- /dev/null +++ b/docs/examples/2EDA_from_r_run.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8f0e472a-a63a-4b91-836f-f0ac12f6bfce", + "metadata": {}, + "source": [ + "# BOA Provided Visualizations" + ] + }, + { + "cell_type": "markdown", + "id": "038f4c1b-3a42-4686-8433-2f803d03cb85", + "metadata": { + "tags": [] + }, + "source": [ + "## Our scheduler.json\n", + "\n", + "From our run in R in [Running an R Script with BOA](1run_r_streamlined.ipynb), we saved our scheduler.json file. In the same directory BOA also saves an optimization.csv file with the parameters and objective of every trial, as well as a log file.\n", + "\n", + "BOA gives us some light EDA tools automatically. You can do them automatically from the command line, or if you would like to dive into with more control, see our Python loading and visualization tutorials for more details.\n", + "\n", + "From the command line, we can issue\n", + "\n", + "```python\n", + "python -m boa.plot --scheduler-path path/to/scheduler.json\n", + "\n", + "or\n", + "\n", + "python -m boa.plot -sp path/to/scheduler.json\n", + "```\n", + "\n", + "```{attention} \n", + "Pictures of the rendered Visualization app will be added in the Future\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa16f066-856a-4d69-9237-fed71c325724", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:boa-dev]", + "language": "python", + "name": "conda-env-boa-dev-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/examples/index.rst b/docs/examples/index.rst index 59d1a3f..9ab6c1c 100644 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -8,6 +8,7 @@ Examples example_py_run 1run_r_streamlined + 2EDA_from_r_run .. toctree:: diff --git a/docs/user_guide/package_overview.rst b/docs/user_guide/package_overview.rst index 1847bf0..02f1f6a 100644 --- a/docs/user_guide/package_overview.rst +++ b/docs/user_guide/package_overview.rst @@ -65,7 +65,7 @@ or:: python -m boa -c path/to/your/config/file -:doc:`BOA's ` will save the its current state automatically to a `scheduler.json` file in your output experiment directory every 1-few trials (depending on parallelism settings). The console will output the Output directory at the start and end of your runs to the console, it will also throughout the run, whenever it saves the `scheduler.json` file, output to the console the location where the file is being saved. You can resume a stopped run from a scheduler file:: +:doc:`BOA's ` will save the its current state automatically to a `scheduler.json` file in your output experiment directory every 1-few trials (depending on parallelism settings). It will also save a optimization.csv at the end of your run with the trial information as well in the same directory as scheduler.json. The console will output the Output directory at the start and end of your runs to the console, it will also throughout the run, whenever it saves the `scheduler.json` file, output to the console the location where the file is being saved. You can resume a stopped run from a scheduler file:: python -m boa --scheduler-path path/to/your/scheduler.json