holobench 1.41.0__py3-none-any.whl → 1.43.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bencher/__init__.py +20 -2
- bencher/bench_cfg.py +262 -54
- bencher/bench_report.py +2 -2
- bencher/bench_runner.py +96 -10
- bencher/bencher.py +421 -89
- bencher/class_enum.py +70 -7
- bencher/example/example_dataframe.py +2 -2
- bencher/example/example_levels.py +17 -173
- bencher/example/example_pareto.py +107 -31
- bencher/example/example_rerun2.py +1 -1
- bencher/example/example_simple_bool.py +2 -2
- bencher/example/example_simple_float2d.py +6 -1
- bencher/example/example_video.py +2 -0
- bencher/example/experimental/example_hvplot_explorer.py +2 -2
- bencher/example/inputs_0D/example_0_in_1_out.py +25 -15
- bencher/example/inputs_0D/example_0_in_2_out.py +12 -3
- bencher/example/inputs_0_float/example_0_cat_in_2_out.py +88 -0
- bencher/example/inputs_0_float/example_1_cat_in_2_out.py +98 -0
- bencher/example/inputs_0_float/example_2_cat_in_2_out.py +107 -0
- bencher/example/inputs_0_float/example_3_cat_in_2_out.py +111 -0
- bencher/example/inputs_1D/example1d_common.py +48 -12
- bencher/example/inputs_1D/example_0_float_1_cat.py +33 -0
- bencher/example/inputs_1D/example_1_cat_in_2_out_repeats.py +68 -0
- bencher/example/inputs_1D/example_1_float_2_cat_repeats.py +3 -0
- bencher/example/inputs_1D/example_1_int_in_1_out.py +98 -0
- bencher/example/inputs_1D/example_1_int_in_2_out.py +101 -0
- bencher/example/inputs_1D/example_1_int_in_2_out_repeats.py +99 -0
- bencher/example/inputs_1_float/example_1_float_0_cat_in_2_out.py +117 -0
- bencher/example/inputs_1_float/example_1_float_1_cat_in_2_out.py +124 -0
- bencher/example/inputs_1_float/example_1_float_2_cat_in_2_out.py +132 -0
- bencher/example/inputs_1_float/example_1_float_3_cat_in_2_out.py +140 -0
- bencher/example/inputs_2D/example_2_cat_in_4_out_repeats.py +104 -0
- bencher/example/inputs_2_float/example_2_float_0_cat_in_2_out.py +98 -0
- bencher/example/inputs_2_float/example_2_float_1_cat_in_2_out.py +112 -0
- bencher/example/inputs_2_float/example_2_float_2_cat_in_2_out.py +122 -0
- bencher/example/inputs_2_float/example_2_float_3_cat_in_2_out.py +138 -0
- bencher/example/inputs_3_float/example_3_float_0_cat_in_2_out.py +111 -0
- bencher/example/inputs_3_float/example_3_float_1_cat_in_2_out.py +117 -0
- bencher/example/inputs_3_float/example_3_float_2_cat_in_2_out.py +124 -0
- bencher/example/inputs_3_float/example_3_float_3_cat_in_2_out.py +129 -0
- bencher/example/meta/generate_examples.py +118 -7
- bencher/example/meta/generate_meta.py +88 -40
- bencher/job.py +174 -9
- bencher/plotting/plot_filter.py +52 -17
- bencher/results/bench_result.py +117 -25
- bencher/results/bench_result_base.py +117 -8
- bencher/results/dataset_result.py +6 -200
- bencher/results/explorer_result.py +23 -0
- bencher/results/{hvplot_result.py → histogram_result.py} +3 -18
- bencher/results/holoview_results/__init__.py +0 -0
- bencher/results/holoview_results/bar_result.py +79 -0
- bencher/results/holoview_results/curve_result.py +110 -0
- bencher/results/holoview_results/distribution_result/__init__.py +0 -0
- bencher/results/holoview_results/distribution_result/box_whisker_result.py +73 -0
- bencher/results/holoview_results/distribution_result/distribution_result.py +109 -0
- bencher/results/holoview_results/distribution_result/scatter_jitter_result.py +92 -0
- bencher/results/holoview_results/distribution_result/violin_result.py +70 -0
- bencher/results/holoview_results/heatmap_result.py +319 -0
- bencher/results/holoview_results/holoview_result.py +346 -0
- bencher/results/holoview_results/line_result.py +240 -0
- bencher/results/holoview_results/scatter_result.py +107 -0
- bencher/results/holoview_results/surface_result.py +158 -0
- bencher/results/holoview_results/table_result.py +14 -0
- bencher/results/holoview_results/tabulator_result.py +20 -0
- bencher/results/optuna_result.py +30 -115
- bencher/results/video_controls.py +38 -0
- bencher/results/video_result.py +39 -36
- bencher/results/video_summary.py +2 -2
- bencher/results/{plotly_result.py → volume_result.py} +29 -8
- bencher/utils.py +175 -26
- bencher/variables/inputs.py +122 -15
- bencher/video_writer.py +2 -1
- bencher/worker_job.py +31 -3
- {holobench-1.41.0.dist-info → holobench-1.43.0.dist-info}/METADATA +24 -24
- holobench-1.43.0.dist-info/RECORD +147 -0
- bencher/example/example_levels2.py +0 -37
- bencher/example/inputs_1D/example_1_in_1_out.py +0 -62
- bencher/example/inputs_1D/example_1_in_2_out.py +0 -63
- bencher/example/inputs_1D/example_1_in_2_out_repeats.py +0 -61
- bencher/results/holoview_result.py +0 -796
- bencher/results/panel_result.py +0 -41
- holobench-1.41.0.dist-info/RECORD +0 -114
- {holobench-1.41.0.dist-info → holobench-1.43.0.dist-info}/WHEEL +0 -0
- {holobench-1.41.0.dist-info → holobench-1.43.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
import logging
|
3
|
+
from typing import Optional
|
4
|
+
import panel as pn
|
5
|
+
import holoviews as hv
|
6
|
+
from param import Parameter
|
7
|
+
import hvplot.xarray # noqa pylint: disable=duplicate-code,unused-import
|
8
|
+
import xarray as xr
|
9
|
+
|
10
|
+
from bencher.results.bench_result_base import ReduceType
|
11
|
+
from bencher.plotting.plot_filter import PlotFilter, VarRange
|
12
|
+
from bencher.variables.results import ResultVar
|
13
|
+
from bencher.results.holoview_results.holoview_result import HoloviewResult
|
14
|
+
|
15
|
+
|
16
|
+
class SurfaceResult(HoloviewResult):
|
17
|
+
"""A class for creating 3D surface plots from benchmark results.
|
18
|
+
|
19
|
+
This class provides methods to visualize benchmark data as 3D surface plots,
|
20
|
+
which are useful for showing relationships between two input variables and
|
21
|
+
a result variable. Surface plots can also display standard deviation bounds
|
22
|
+
when benchmark runs include multiple repetitions.
|
23
|
+
"""
|
24
|
+
|
25
|
+
def to_plot(
|
26
|
+
self, result_var: Parameter = None, override: bool = True, **kwargs
|
27
|
+
) -> Optional[pn.pane.Pane]:
|
28
|
+
"""Generates a 3D surface plot from benchmark data.
|
29
|
+
|
30
|
+
This is a convenience method that calls to_surface() with the same parameters.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
result_var (Parameter, optional): The result variable to plot. If None, uses the default.
|
34
|
+
override (bool, optional): Whether to override filter restrictions. Defaults to True.
|
35
|
+
**kwargs: Additional keyword arguments passed to the plot rendering.
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
Optional[pn.pane.Pane]: A panel containing the surface plot if data is appropriate,
|
39
|
+
otherwise returns filter match results.
|
40
|
+
"""
|
41
|
+
return self.to_surface(result_var=result_var, override=override, **kwargs)
|
42
|
+
|
43
|
+
def to_surface(
|
44
|
+
self, result_var: Parameter = None, override: bool = True, **kwargs
|
45
|
+
) -> Optional[pn.pane.Pane]:
|
46
|
+
"""Generates a 3D surface plot from benchmark data.
|
47
|
+
|
48
|
+
This method applies filters to ensure the data is appropriate for a surface plot
|
49
|
+
and then passes the filtered data to to_surface_ds for rendering.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
result_var (Parameter, optional): The result variable to plot. If None, uses the default.
|
53
|
+
override (bool, optional): Whether to override filter restrictions. Defaults to True.
|
54
|
+
**kwargs: Additional keyword arguments passed to the plot rendering.
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
Optional[pn.pane.Pane]: A panel containing the surface plot if data is appropriate,
|
58
|
+
otherwise returns filter match results.
|
59
|
+
"""
|
60
|
+
return self.filter(
|
61
|
+
self.to_surface_ds,
|
62
|
+
float_range=VarRange(2, None),
|
63
|
+
cat_range=VarRange(0, None),
|
64
|
+
input_range=VarRange(1, None),
|
65
|
+
reduce=ReduceType.REDUCE,
|
66
|
+
target_dimension=2,
|
67
|
+
result_var=result_var,
|
68
|
+
result_types=(ResultVar),
|
69
|
+
override=override,
|
70
|
+
**kwargs,
|
71
|
+
)
|
72
|
+
|
73
|
+
def to_surface_ds(
|
74
|
+
self,
|
75
|
+
dataset: xr.Dataset,
|
76
|
+
result_var: Parameter,
|
77
|
+
override: bool = True,
|
78
|
+
alpha: float = 0.3,
|
79
|
+
**kwargs,
|
80
|
+
) -> Optional[pn.panel]:
|
81
|
+
"""Creates a 3D surface plot from the provided dataset.
|
82
|
+
|
83
|
+
Given a filtered dataset, this method generates a 3D surface visualization showing
|
84
|
+
the relationship between two input variables and the result variable. When multiple
|
85
|
+
benchmark repetitions are available, standard deviation bounds can also be displayed.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
dataset (xr.Dataset): The dataset containing benchmark results.
|
89
|
+
result_var (Parameter): The result variable to plot.
|
90
|
+
override (bool, optional): Whether to override filter restrictions. Defaults to True.
|
91
|
+
alpha (float, optional): The transparency level for standard deviation surfaces. Defaults to 0.3.
|
92
|
+
**kwargs: Additional keyword arguments passed to the surface plot options.
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
Optional[pn.panel]: A panel containing the surface plot if data matches criteria,
|
96
|
+
otherwise returns filter match results.
|
97
|
+
"""
|
98
|
+
matches_res = PlotFilter(
|
99
|
+
float_range=VarRange(2, 2),
|
100
|
+
cat_range=VarRange(0, None),
|
101
|
+
vector_len=VarRange(1, 1),
|
102
|
+
result_vars=VarRange(1, 1),
|
103
|
+
).matches_result(self.plt_cnt_cfg, "to_surface_hv", override)
|
104
|
+
if matches_res.overall:
|
105
|
+
# xr_cfg = plot_float_cnt_2(self.plt_cnt_cfg, result_var)
|
106
|
+
|
107
|
+
# TODO a warning suggests setting this parameter, but it does not seem to help as expected, leaving here to fix in the future
|
108
|
+
# hv.config.image_rtol = 1.0
|
109
|
+
|
110
|
+
mean = dataset[result_var.name]
|
111
|
+
|
112
|
+
hvds = hv.Dataset(dataset[result_var.name])
|
113
|
+
|
114
|
+
x = self.plt_cnt_cfg.float_vars[0]
|
115
|
+
y = self.plt_cnt_cfg.float_vars[1]
|
116
|
+
|
117
|
+
try:
|
118
|
+
surface = hvds.to(hv.Surface, vdims=[result_var.name])
|
119
|
+
surface = surface.opts(colorbar=True)
|
120
|
+
except Exception as e: # pylint: disable=broad-except
|
121
|
+
logging.warning(e)
|
122
|
+
|
123
|
+
if self.bench_cfg.repeats > 1:
|
124
|
+
std_dev = dataset[f"{result_var.name}_std"]
|
125
|
+
|
126
|
+
upper = mean + std_dev
|
127
|
+
upper.name = result_var.name
|
128
|
+
|
129
|
+
lower = mean - std_dev
|
130
|
+
lower.name = result_var.name
|
131
|
+
|
132
|
+
surface *= (
|
133
|
+
hv.Dataset(upper)
|
134
|
+
.to(hv.Surface)
|
135
|
+
.opts(alpha=alpha, colorbar=False, backend="plotly")
|
136
|
+
)
|
137
|
+
surface *= (
|
138
|
+
hv.Dataset(lower)
|
139
|
+
.to(hv.Surface)
|
140
|
+
.opts(alpha=alpha, colorbar=False, backend="plotly")
|
141
|
+
)
|
142
|
+
|
143
|
+
surface = surface.opts(
|
144
|
+
zlabel=f"{result_var.name} [{result_var.units}]",
|
145
|
+
title=f"{result_var.name} vs ({x.name} and {y.name})",
|
146
|
+
backend="plotly",
|
147
|
+
**kwargs,
|
148
|
+
)
|
149
|
+
|
150
|
+
if self.bench_cfg.render_plotly:
|
151
|
+
hv.extension("plotly")
|
152
|
+
out = surface
|
153
|
+
else:
|
154
|
+
# using render disabled the holoviews sliders :(
|
155
|
+
out = hv.render(surface, backend="plotly")
|
156
|
+
return pn.Column(out, name="surface_hv")
|
157
|
+
|
158
|
+
return matches_res.to_panel()
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
import holoviews as hv
|
3
|
+
from bencher.results.bench_result_base import ReduceType
|
4
|
+
from bencher.results.holoview_results.holoview_result import HoloviewResult
|
5
|
+
|
6
|
+
|
7
|
+
class TableResult(HoloviewResult):
|
8
|
+
def to_plot(self, **kwargs) -> hv.Table: # pylint:disable=unused-argument
|
9
|
+
"""Convert the dataset to a Table visualization.
|
10
|
+
|
11
|
+
Returns:
|
12
|
+
hv.Table: A HoloViews Table object.
|
13
|
+
"""
|
14
|
+
return self.to_hv_type(hv.Table, ReduceType.SQUEEZE)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
import panel as pn
|
3
|
+
|
4
|
+
from bencher.results.holoview_results.holoview_result import HoloviewResult
|
5
|
+
|
6
|
+
|
7
|
+
class TabulatorResult(HoloviewResult):
|
8
|
+
def to_plot(self, **kwargs) -> pn.widgets.Tabulator: # pylint:disable=unused-argument
|
9
|
+
"""Create an interactive table visualization of the data.
|
10
|
+
|
11
|
+
Passes the data to the panel Tabulator type to display an interactive table.
|
12
|
+
See https://panel.holoviz.org/reference/widgets/Tabulator.html for extra options.
|
13
|
+
|
14
|
+
Args:
|
15
|
+
**kwargs: Additional parameters to pass to the Tabulator constructor.
|
16
|
+
|
17
|
+
Returns:
|
18
|
+
pn.widgets.Tabulator: An interactive table widget.
|
19
|
+
"""
|
20
|
+
return pn.widgets.Tabulator(self.to_pandas())
|
bencher/results/optuna_result.py
CHANGED
@@ -5,11 +5,6 @@ from copy import deepcopy
|
|
5
5
|
import numpy as np
|
6
6
|
import optuna
|
7
7
|
import panel as pn
|
8
|
-
from collections import defaultdict
|
9
|
-
from textwrap import wrap
|
10
|
-
|
11
|
-
import pandas as pd
|
12
|
-
import xarray as xr
|
13
8
|
|
14
9
|
|
15
10
|
from optuna.visualization import (
|
@@ -18,9 +13,7 @@ from optuna.visualization import (
|
|
18
13
|
)
|
19
14
|
from bencher.utils import hmap_canonical_input
|
20
15
|
from bencher.variables.time import TimeSnapshot, TimeEvent
|
21
|
-
from bencher.
|
22
|
-
from bencher.plotting.plt_cnt_cfg import PltCntCfg
|
23
|
-
|
16
|
+
from bencher.results.bench_result_base import BenchResultBase, ReduceType
|
24
17
|
|
25
18
|
# from bencher.results.bench_result_base import BenchResultBase
|
26
19
|
from bencher.optuna_conversions import (
|
@@ -33,97 +26,15 @@ from bencher.optuna_conversions import (
|
|
33
26
|
)
|
34
27
|
|
35
28
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
Args:
|
40
|
-
dataarray (xr.DataArray): dataarray with boolean coordinates
|
41
|
-
|
42
|
-
Returns:
|
43
|
-
xr.DataArray: dataarray with boolean coordinates converted to strings
|
44
|
-
"""
|
45
|
-
bool_coords = {}
|
46
|
-
for c in dataset.coords:
|
47
|
-
if dataset.coords[c].dtype == bool:
|
48
|
-
bool_coords[c] = [str(vals) for vals in dataset.coords[c].values]
|
49
|
-
|
50
|
-
if len(bool_coords) > 0:
|
51
|
-
return dataset.assign_coords(bool_coords)
|
52
|
-
return dataset
|
53
|
-
|
54
|
-
|
55
|
-
class OptunaResult:
|
56
|
-
def __init__(self, bench_cfg: BenchCfg) -> None:
|
57
|
-
self.bench_cfg = bench_cfg
|
58
|
-
# self.wrap_long_time_labels(bench_cfg) # todo remove
|
59
|
-
self.ds = xr.Dataset()
|
60
|
-
self.object_index = []
|
61
|
-
self.hmaps = defaultdict(dict)
|
62
|
-
self.result_hmaps = bench_cfg.result_hmaps
|
63
|
-
self.studies = []
|
64
|
-
self.plt_cnt_cfg = PltCntCfg()
|
65
|
-
self.plot_inputs = []
|
66
|
-
self.dataset_list = []
|
67
|
-
|
68
|
-
# self.width=600/
|
69
|
-
# self.height=600
|
70
|
-
|
71
|
-
# bench_res.objects.append(rv)
|
72
|
-
# bench_res.reference_index = len(bench_res.objects)
|
73
|
-
|
74
|
-
def post_setup(self):
|
75
|
-
self.plt_cnt_cfg = PltCntCfg.generate_plt_cnt_cfg(self.bench_cfg)
|
76
|
-
self.bench_cfg = self.wrap_long_time_labels(self.bench_cfg)
|
77
|
-
self.ds = convert_dataset_bool_dims_to_str(self.ds)
|
78
|
-
|
79
|
-
def to_xarray(self) -> xr.Dataset:
|
80
|
-
return self.ds
|
81
|
-
|
82
|
-
def setup_object_index(self):
|
83
|
-
self.object_index = []
|
84
|
-
|
85
|
-
def to_pandas(self, reset_index=True) -> pd.DataFrame:
|
86
|
-
"""Get the xarray results as a pandas dataframe
|
87
|
-
|
88
|
-
Returns:
|
89
|
-
pd.DataFrame: The xarray results array as a pandas dataframe
|
90
|
-
"""
|
91
|
-
ds = self.to_xarray().to_dataframe()
|
92
|
-
if reset_index:
|
93
|
-
return ds.reset_index()
|
94
|
-
return ds
|
95
|
-
|
96
|
-
def wrap_long_time_labels(self, bench_cfg):
|
97
|
-
"""Takes a benchCfg and wraps any index labels that are too long to be plotted easily
|
98
|
-
|
99
|
-
Args:
|
100
|
-
bench_cfg (BenchCfg):
|
101
|
-
|
102
|
-
Returns:
|
103
|
-
BenchCfg: updated config with wrapped labels
|
104
|
-
"""
|
105
|
-
if bench_cfg.over_time:
|
106
|
-
if self.ds.coords["over_time"].dtype == np.datetime64:
|
107
|
-
# plotly catastrophically fails to plot anything with the default long string representation of time, so convert to a shorter time representation
|
108
|
-
self.ds.coords["over_time"] = [
|
109
|
-
pd.to_datetime(t).strftime("%d-%m-%y %H-%M-%S")
|
110
|
-
for t in self.ds.coords["over_time"].values
|
111
|
-
]
|
112
|
-
# wrap very long time event labels because otherwise the graphs are unreadable
|
113
|
-
if bench_cfg.time_event is not None:
|
114
|
-
self.ds.coords["over_time"] = [
|
115
|
-
"\n".join(wrap(t, 20)) for t in self.ds.coords["over_time"].values
|
116
|
-
]
|
117
|
-
return bench_cfg
|
118
|
-
|
119
|
-
def to_optuna_plots(self) -> List[pn.pane.panel]:
|
29
|
+
class OptunaResult(BenchResultBase):
|
30
|
+
def to_optuna_plots(self, **kwargs) -> List[pn.pane.panel]:
|
120
31
|
"""Create an optuna summary from the benchmark results
|
121
32
|
|
122
33
|
Returns:
|
123
34
|
List[pn.pane.panel]: A list of optuna plot summarising the benchmark process
|
124
35
|
"""
|
125
36
|
|
126
|
-
return self.collect_optuna_plots()
|
37
|
+
return self.collect_optuna_plots(**kwargs)
|
127
38
|
|
128
39
|
def to_optuna_from_sweep(self, bench, n_trials=30):
|
129
40
|
optu = self.to_optuna_from_results(
|
@@ -175,7 +86,8 @@ class OptunaResult:
|
|
175
86
|
optuna.Study: optuna description of the study
|
176
87
|
"""
|
177
88
|
if include_meta:
|
178
|
-
df = self.to_pandas()
|
89
|
+
# df = self.to_pandas()
|
90
|
+
df = self.to_dataset(reduce=ReduceType.NONE).to_dataframe().reset_index()
|
179
91
|
all_vars = []
|
180
92
|
for v in self.bench_cfg.all_vars:
|
181
93
|
if type(v) is not TimeEvent:
|
@@ -189,11 +101,15 @@ class OptunaResult:
|
|
189
101
|
# if self.bench_cfg.repeats>1:
|
190
102
|
# df = self.bench_cfg.ds.mean("repeat").to_dataframe().reset_index()
|
191
103
|
# else:
|
192
|
-
df = self.to_pandas().reset_index()
|
104
|
+
# df = self.to_pandas().reset_index()
|
105
|
+
df = self.to_dataset(reduce=ReduceType.AUTO).to_dataframe().reset_index()
|
193
106
|
# df = self.bench_cfg.ds.mean("repeat").to_dataframe.reset_index()
|
194
107
|
# self.bench_cfg.all_vars
|
195
108
|
# del self.bench_cfg.meta_vars[1]
|
196
109
|
|
110
|
+
# optuna does not like the nan values so remove them.
|
111
|
+
df.dropna(inplace=True)
|
112
|
+
|
197
113
|
trials = []
|
198
114
|
distributions = {}
|
199
115
|
for i in all_vars:
|
@@ -210,6 +126,9 @@ class OptunaResult:
|
|
210
126
|
params[i.name] = row[1][i.name]
|
211
127
|
|
212
128
|
for r in self.bench_cfg.optuna_targets():
|
129
|
+
# print(row[1][r])
|
130
|
+
# print(np.isnan(row[1][r]))
|
131
|
+
# if not np.isnan(row[1][r]):
|
213
132
|
values.append(row[1][r])
|
214
133
|
|
215
134
|
trials.append(
|
@@ -245,7 +164,9 @@ class OptunaResult:
|
|
245
164
|
def get_pareto_front_params(self):
|
246
165
|
return [p.params for p in self.studies[0].trials]
|
247
166
|
|
248
|
-
def collect_optuna_plots(
|
167
|
+
def collect_optuna_plots(
|
168
|
+
self, pareto_width: float = None, pareto_height: float = None
|
169
|
+
) -> List[pn.pane.panel]:
|
249
170
|
"""Use optuna to plot various summaries of the optimisation
|
250
171
|
|
251
172
|
Args:
|
@@ -292,11 +213,18 @@ class OptunaResult:
|
|
292
213
|
include_dominated_trials=False,
|
293
214
|
)
|
294
215
|
)
|
216
|
+
if pareto_width is not None:
|
217
|
+
study_pane[-1].width = pareto_width
|
218
|
+
if pareto_height is not None:
|
219
|
+
study_pane[-1].height = pareto_height
|
220
|
+
try:
|
221
|
+
study_pane.append(param_importance(self.bench_cfg, study))
|
222
|
+
param_str.append(
|
223
|
+
f" Number of trials on the Pareto front: {len(study.best_trials)}"
|
224
|
+
)
|
225
|
+
except RuntimeError as e:
|
226
|
+
study_pane.append(f"Error generating parameter importance: {str(e)}")
|
295
227
|
|
296
|
-
study_pane.append(param_importance(self.bench_cfg, study))
|
297
|
-
param_str.append(
|
298
|
-
f" Number of trials on the Pareto front: {len(study.best_trials)}"
|
299
|
-
)
|
300
228
|
for t in study.best_trials:
|
301
229
|
param_str.extend(summarise_trial(t, self.bench_cfg))
|
302
230
|
|
@@ -343,18 +271,5 @@ class OptunaResult:
|
|
343
271
|
"""Return a deep copy of these results"""
|
344
272
|
return deepcopy(self)
|
345
273
|
|
346
|
-
def
|
347
|
-
|
348
|
-
if self.bench_cfg.plot_size is not None:
|
349
|
-
kwargs["width"] = self.bench_cfg.plot_size
|
350
|
-
# specific width overrides general size
|
351
|
-
if self.bench_cfg.plot_width is not None:
|
352
|
-
kwargs["width"] = self.bench_cfg.plot_width
|
353
|
-
|
354
|
-
if "height" not in kwargs:
|
355
|
-
if self.bench_cfg.plot_size is not None:
|
356
|
-
kwargs["height"] = self.bench_cfg.plot_size
|
357
|
-
# specific height overrides general size
|
358
|
-
if self.bench_cfg.plot_height is not None:
|
359
|
-
kwargs["height"] = self.bench_cfg.plot_height
|
360
|
-
return kwargs
|
274
|
+
def get_best_holomap(self, name: str = None):
|
275
|
+
return self.get_hmap(name)[self.get_best_trial_params(True)]
|
@@ -0,0 +1,38 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
from pathlib import Path
|
3
|
+
import panel as pn
|
4
|
+
|
5
|
+
|
6
|
+
class VideoControls:
|
7
|
+
def __init__(self) -> None:
|
8
|
+
self.vid_p = []
|
9
|
+
|
10
|
+
def video_container(self, path, **kwargs):
|
11
|
+
if path is not None and Path(path).exists():
|
12
|
+
vid = pn.pane.Video(path, autoplay=True, **kwargs)
|
13
|
+
vid.loop = True
|
14
|
+
self.vid_p.append(vid)
|
15
|
+
return vid
|
16
|
+
return pn.pane.Markdown(f"video does not exist {path}")
|
17
|
+
|
18
|
+
def video_controls(self) -> Optional[pn.Column]:
|
19
|
+
def play_vid(_): # pragma: no cover
|
20
|
+
for r in self.vid_p:
|
21
|
+
r.paused = False
|
22
|
+
|
23
|
+
def reset_vid(_): # pragma: no cover
|
24
|
+
for r in self.vid_p:
|
25
|
+
r.paused = False
|
26
|
+
r.time = 0
|
27
|
+
|
28
|
+
button_names = ["Play Videos", "Pause Videos", "Loop Videos", "Reset Videos"]
|
29
|
+
buttom_cb = [play_vid, reset_vid]
|
30
|
+
|
31
|
+
buttons = pn.Row()
|
32
|
+
|
33
|
+
for name, cb in zip(button_names, buttom_cb):
|
34
|
+
button = pn.widgets.Button(name=name)
|
35
|
+
pn.bind(cb, button, watch=True)
|
36
|
+
buttons.append(button)
|
37
|
+
|
38
|
+
return pn.Column(buttons)
|
bencher/results/video_result.py
CHANGED
@@ -1,38 +1,41 @@
|
|
1
1
|
from typing import Optional
|
2
|
-
from
|
2
|
+
from functools import partial
|
3
3
|
import panel as pn
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
return pn.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
4
|
+
from param import Parameter
|
5
|
+
import holoviews as hv
|
6
|
+
from bencher.results.bench_result_base import BenchResultBase, ReduceType
|
7
|
+
from bencher.results.video_controls import VideoControls
|
8
|
+
from bencher.variables.results import (
|
9
|
+
PANEL_TYPES,
|
10
|
+
)
|
11
|
+
|
12
|
+
|
13
|
+
class VideoResult(BenchResultBase):
|
14
|
+
def to_video(self, result_var: Parameter = None, **kwargs):
|
15
|
+
vc = VideoControls()
|
16
|
+
return pn.Column(
|
17
|
+
vc.video_controls(),
|
18
|
+
self.to_panes(result_var=result_var, container=vc.video_container, **kwargs),
|
19
|
+
)
|
20
|
+
|
21
|
+
def to_panes(
|
22
|
+
self,
|
23
|
+
result_var: Parameter = None,
|
24
|
+
hv_dataset=None,
|
25
|
+
target_dimension: int = 0,
|
26
|
+
container=None,
|
27
|
+
level: int = None,
|
28
|
+
**kwargs,
|
29
|
+
) -> Optional[pn.pane.panel]:
|
30
|
+
if hv_dataset is None:
|
31
|
+
hv_dataset = self.to_hv_dataset(ReduceType.SQUEEZE, level=level)
|
32
|
+
elif not isinstance(hv_dataset, hv.Dataset):
|
33
|
+
hv_dataset = hv.Dataset(hv_dataset)
|
34
|
+
return self.map_plot_panes(
|
35
|
+
partial(self.ds_to_container, container=container),
|
36
|
+
hv_dataset=hv_dataset,
|
37
|
+
target_dimension=target_dimension,
|
38
|
+
result_var=result_var,
|
39
|
+
result_types=PANEL_TYPES,
|
40
|
+
**kwargs,
|
41
|
+
)
|
bencher/results/video_summary.py
CHANGED
@@ -8,7 +8,7 @@ from bencher.variables.results import ResultImage
|
|
8
8
|
from bencher.plotting.plot_filter import VarRange, PlotFilter
|
9
9
|
from bencher.utils import callable_name, int_to_col, color_tuple_to_255
|
10
10
|
from bencher.video_writer import VideoWriter
|
11
|
-
from bencher.results.
|
11
|
+
from bencher.results.video_controls import VideoControls
|
12
12
|
from bencher.results.composable_container.composable_container_video import (
|
13
13
|
ComposableContainerVideo,
|
14
14
|
ComposeType,
|
@@ -60,7 +60,7 @@ class VideoSummaryResult(BenchResultBase):
|
|
60
60
|
input_range=VarRange(1, None),
|
61
61
|
)
|
62
62
|
matches_res = plot_filter.matches_result(
|
63
|
-
self.plt_cnt_cfg, callable_name(self.to_video_grid_ds)
|
63
|
+
self.plt_cnt_cfg, callable_name(self.to_video_grid_ds), override=False
|
64
64
|
)
|
65
65
|
|
66
66
|
if pane_collection is None:
|
@@ -1,29 +1,50 @@
|
|
1
|
-
import
|
2
|
-
import plotly.graph_objs as go
|
3
|
-
from typing import Optional
|
4
|
-
import xarray as xr
|
1
|
+
from typing import Optional, Any
|
5
2
|
|
3
|
+
import xarray as xr
|
6
4
|
from param import Parameter
|
5
|
+
import panel as pn
|
6
|
+
import plotly.graph_objs as go
|
7
7
|
|
8
8
|
from bencher.plotting.plot_filter import VarRange
|
9
9
|
from bencher.results.bench_result_base import BenchResultBase, ReduceType
|
10
10
|
from bencher.variables.results import ResultVar
|
11
11
|
|
12
12
|
|
13
|
-
class
|
14
|
-
def
|
13
|
+
class VolumeResult(BenchResultBase):
|
14
|
+
def to_plot(
|
15
|
+
self, result_var: Optional[Parameter] = None, override: bool = True, **kwargs: Any
|
16
|
+
) -> Optional[pn.panel]:
|
17
|
+
"""Generates a 3d volume plot from benchmark data.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
result_var (Optional[Parameter]): The result variable to plot. If None, uses the default.
|
21
|
+
override (bool): Whether to override filter restrictions. Defaults to True.
|
22
|
+
**kwargs (Any): Additional keyword arguments passed to the plot rendering.
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
Optional[pn.panel]: A panel containing the volume plot if data is appropriate,
|
26
|
+
otherwise returns filter match results.
|
27
|
+
"""
|
28
|
+
return self.to_volume(
|
29
|
+
result_var=result_var,
|
30
|
+
override=override,
|
31
|
+
**kwargs,
|
32
|
+
)
|
33
|
+
|
34
|
+
def to_volume(self, result_var: Parameter = None, override: bool = True, **kwargs):
|
15
35
|
return self.filter(
|
16
|
-
self.
|
36
|
+
self.to_volume_ds,
|
17
37
|
float_range=VarRange(3, 3),
|
18
38
|
cat_range=VarRange(-1, 0),
|
19
39
|
reduce=ReduceType.REDUCE,
|
20
40
|
target_dimension=3,
|
21
41
|
result_var=result_var,
|
22
42
|
result_types=(ResultVar),
|
43
|
+
override=override,
|
23
44
|
**kwargs,
|
24
45
|
)
|
25
46
|
|
26
|
-
def
|
47
|
+
def to_volume_ds(
|
27
48
|
self, dataset: xr.Dataset, result_var: Parameter, width=600, height=600
|
28
49
|
) -> Optional[pn.pane.Plotly]:
|
29
50
|
"""Given a benchCfg generate a 3D surface plot
|