holobench 1.19.0__py2.py3-none-any.whl → 1.30.1__py2.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 +12 -1
- bencher/bench_report.py +6 -109
- bencher/bench_runner.py +1 -1
- bencher/bencher.py +103 -57
- bencher/example/benchmark_data.py +0 -4
- bencher/example/example_composable_container.py +106 -0
- bencher/example/example_composable_container2.py +160 -0
- bencher/example/example_consts.py +39 -0
- bencher/example/example_custom_sweep2.py +42 -0
- bencher/example/example_dataframe.py +48 -0
- bencher/example/example_image.py +32 -17
- bencher/example/example_image1.py +81 -0
- bencher/example/example_levels2.py +37 -0
- bencher/example/example_simple_float.py +15 -25
- bencher/example/example_simple_float2d.py +29 -0
- bencher/example/example_strings.py +3 -2
- bencher/example/example_video.py +2 -11
- bencher/example/meta/example_meta.py +2 -2
- bencher/example/meta/example_meta_cat.py +2 -2
- bencher/example/meta/example_meta_float.py +1 -1
- bencher/example/meta/example_meta_levels.py +2 -2
- bencher/optuna_conversions.py +3 -2
- bencher/plotting/plt_cnt_cfg.py +1 -0
- bencher/results/bench_result.py +3 -1
- bencher/results/bench_result_base.py +58 -8
- bencher/results/composable_container/composable_container_base.py +25 -12
- bencher/results/composable_container/composable_container_dataframe.py +52 -0
- bencher/results/composable_container/composable_container_panel.py +17 -18
- bencher/results/composable_container/composable_container_video.py +163 -55
- bencher/results/dataset_result.py +227 -0
- bencher/results/holoview_result.py +15 -7
- bencher/results/optuna_result.py +4 -3
- bencher/results/panel_result.py +1 -1
- bencher/results/video_summary.py +104 -99
- bencher/utils.py +28 -2
- bencher/variables/__init__.py +0 -0
- bencher/variables/inputs.py +24 -1
- bencher/variables/parametrised_sweep.py +6 -4
- bencher/variables/results.py +29 -1
- bencher/variables/time.py +22 -0
- bencher/video_writer.py +20 -74
- {holobench-1.19.0.dist-info → holobench-1.30.1.dist-info}/METADATA +77 -35
- {holobench-1.19.0.dist-info → holobench-1.30.1.dist-info}/RECORD +46 -33
- {holobench-1.19.0.dist-info → holobench-1.30.1.dist-info}/WHEEL +1 -1
- holobench-1.30.1.dist-info/licenses/LICENSE +21 -0
- resource/bencher +0 -0
@@ -0,0 +1,227 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
import panel as pn
|
3
|
+
from param import Parameter
|
4
|
+
from bencher.results.bench_result_base import BenchResultBase, ReduceType
|
5
|
+
|
6
|
+
|
7
|
+
from functools import partial
|
8
|
+
import holoviews as hv
|
9
|
+
from bencher.variables.results import (
|
10
|
+
PANEL_TYPES,
|
11
|
+
)
|
12
|
+
|
13
|
+
|
14
|
+
class DataSetResult(BenchResultBase):
|
15
|
+
def to_dataset1(
|
16
|
+
self,
|
17
|
+
result_var: Parameter = None,
|
18
|
+
hv_dataset=None,
|
19
|
+
target_dimension: int = 0,
|
20
|
+
container=None,
|
21
|
+
level: int = None,
|
22
|
+
**kwargs,
|
23
|
+
) -> Optional[pn.pane.panel]:
|
24
|
+
if hv_dataset is None:
|
25
|
+
hv_dataset = self.to_hv_dataset(ReduceType.SQUEEZE, level=level)
|
26
|
+
elif not isinstance(hv_dataset, hv.Dataset):
|
27
|
+
hv_dataset = hv.Dataset(hv_dataset)
|
28
|
+
return self.map_plot_panes(
|
29
|
+
partial(self.ds_to_container, container=container),
|
30
|
+
hv_dataset=hv_dataset,
|
31
|
+
target_dimension=target_dimension,
|
32
|
+
result_var=result_var,
|
33
|
+
result_types=PANEL_TYPES,
|
34
|
+
**kwargs,
|
35
|
+
)
|
36
|
+
|
37
|
+
|
38
|
+
# class DataSetResult(BenchResultBase):
|
39
|
+
|
40
|
+
# def to_datatset(
|
41
|
+
# self,
|
42
|
+
# result_var: Parameter = None,
|
43
|
+
# result_types=(ResultDataSet,),
|
44
|
+
# pane_collection: pn.pane = None,
|
45
|
+
# time_sequence_dimension=0,
|
46
|
+
# target_duration: float = None,
|
47
|
+
# **kwargs,
|
48
|
+
# ) -> Optional[pn.panel]:
|
49
|
+
# """Returns the results compiled into a video
|
50
|
+
|
51
|
+
# Args:
|
52
|
+
# result_var (Parameter, optional): The result var to plot. Defaults to None.
|
53
|
+
# result_types (tuple, optional): The types of result var to convert to video. Defaults to (ResultDataSet,).
|
54
|
+
# collection (pn.pane, optional): If there are multiple results, use this collection to stack them. Defaults to pn.Row().
|
55
|
+
|
56
|
+
# Returns:
|
57
|
+
# Optional[pn.panel]: a panel pane with a video of all results concatenated together
|
58
|
+
# """
|
59
|
+
# plot_filter = PlotFilter(
|
60
|
+
# float_range=VarRange(0, None),
|
61
|
+
# cat_range=VarRange(0, None),
|
62
|
+
# panel_range=VarRange(1, None),
|
63
|
+
# input_range=VarRange(0, None),
|
64
|
+
# )
|
65
|
+
# matches_res = plot_filter.matches_result(
|
66
|
+
# self.plt_cnt_cfg, callable_name(self.to_video_grid_ds)
|
67
|
+
# )
|
68
|
+
|
69
|
+
# if pane_collection is None:
|
70
|
+
# pane_collection = pn.Row()
|
71
|
+
|
72
|
+
# if matches_res.overall:
|
73
|
+
# ds = self.to_dataset(ReduceType.SQUEEZE)
|
74
|
+
# for rv in self.get_results_var_list(result_var):
|
75
|
+
# if isinstance(rv, result_types):
|
76
|
+
# pane_collection.append(
|
77
|
+
# self.to_video_grid_ds(
|
78
|
+
# ds,
|
79
|
+
# rv,
|
80
|
+
# time_sequence_dimension=time_sequence_dimension,
|
81
|
+
# target_duration=target_duration,
|
82
|
+
# **kwargs,
|
83
|
+
# )
|
84
|
+
# )
|
85
|
+
# return pane_collection
|
86
|
+
# return matches_res.to_panel()
|
87
|
+
|
88
|
+
# def to_video_grid_ds(
|
89
|
+
# self,
|
90
|
+
# dataset: xr.Dataset,
|
91
|
+
# result_var: Parameter,
|
92
|
+
# reverse=True,
|
93
|
+
# time_sequence_dimension=0,
|
94
|
+
# video_controls: VideoControls = None,
|
95
|
+
# target_duration: float = None,
|
96
|
+
# **kwargs,
|
97
|
+
# ):
|
98
|
+
# cvc = self._to_video_panes_ds(
|
99
|
+
# dataset,
|
100
|
+
# self.plot_cb,
|
101
|
+
# target_dimension=0,
|
102
|
+
# horizontal=True,
|
103
|
+
# compose_method=ComposeType.right,
|
104
|
+
# time_sequence_dimension=time_sequence_dimension,
|
105
|
+
# result_var=result_var,
|
106
|
+
# final=True,
|
107
|
+
# reverse=reverse,
|
108
|
+
# target_duration=target_duration,
|
109
|
+
# **kwargs,
|
110
|
+
# )
|
111
|
+
|
112
|
+
# filename = VideoWriter().write_video_raw(cvc)
|
113
|
+
|
114
|
+
# if filename is not None:
|
115
|
+
# if video_controls is None:
|
116
|
+
# video_controls = VideoControls()
|
117
|
+
# return video_controls.video_container(
|
118
|
+
# filename, width=kwargs.get("width", None), height=kwargs.get("height", None)
|
119
|
+
# )
|
120
|
+
# return None
|
121
|
+
|
122
|
+
# def plot_cb(self, dataset, result_var, **kwargs):
|
123
|
+
# val = self.ds_to_container(dataset, result_var, container=None, **kwargs)
|
124
|
+
# return val
|
125
|
+
|
126
|
+
# def dataset_to_compose_list(
|
127
|
+
# self,
|
128
|
+
# dataset: xr.Dataset,
|
129
|
+
# first_compose_method: ComposeType = ComposeType.down,
|
130
|
+
# time_sequence_dimension: int = 0,
|
131
|
+
# ) -> List[ComposeType]:
|
132
|
+
# """ "Given a dataset, chose an order for composing the results. By default will flip between right and down and the last dimension will be a time sequence.
|
133
|
+
|
134
|
+
# Args:
|
135
|
+
# dataset (xr.Dataset): the dataset to render
|
136
|
+
# first_compose_method (ComposeType, optional): the direction of the first composition method. Defaults to ComposeType.right.
|
137
|
+
# time_sequence_dimension (int, optional): The dimension to start time sequencing instead of composing in space. Defaults to 0.
|
138
|
+
|
139
|
+
# Returns:
|
140
|
+
# List[ComposeType]: A list of composition methods for composing the dataset result
|
141
|
+
# """
|
142
|
+
|
143
|
+
# num_dims = len(dataset.sizes)
|
144
|
+
# if time_sequence_dimension == -1: # use time sequence for everything
|
145
|
+
# compose_method_list = [ComposeType.sequence] * (num_dims + 1)
|
146
|
+
# else:
|
147
|
+
# compose_method_list = [first_compose_method]
|
148
|
+
# compose_method_list.extend(
|
149
|
+
# ComposeType.flip(compose_method_list[-1]) for _ in range(num_dims - 1)
|
150
|
+
# )
|
151
|
+
# compose_method_list.append(ComposeType.sequence)
|
152
|
+
|
153
|
+
# for i in range(min(len(compose_method_list), time_sequence_dimension + 1)):
|
154
|
+
# compose_method_list[i] = ComposeType.sequence
|
155
|
+
|
156
|
+
# return compose_method_list
|
157
|
+
|
158
|
+
# def _to_video_panes_ds(
|
159
|
+
# self,
|
160
|
+
# dataset: xr.Dataset,
|
161
|
+
# plot_callback: callable = None,
|
162
|
+
# target_dimension=0,
|
163
|
+
# compose_method=ComposeType.right,
|
164
|
+
# compose_method_list=None,
|
165
|
+
# result_var=None,
|
166
|
+
# time_sequence_dimension=0,
|
167
|
+
# root_dimensions=None,
|
168
|
+
# reverse=False,
|
169
|
+
# target_duration: float = None,
|
170
|
+
# **kwargs,
|
171
|
+
# ) -> pn.panel:
|
172
|
+
# num_dims = len(dataset.sizes)
|
173
|
+
# dims = list(d for d in dataset.sizes)
|
174
|
+
# if reverse:
|
175
|
+
# dims = list(reversed(dims))
|
176
|
+
|
177
|
+
# if root_dimensions is None:
|
178
|
+
# root_dimensions = num_dims
|
179
|
+
|
180
|
+
# if compose_method_list is None:
|
181
|
+
# compose_method_list = self.dataset_to_compose_list(
|
182
|
+
# dataset, compose_method, time_sequence_dimension=time_sequence_dimension
|
183
|
+
# )
|
184
|
+
|
185
|
+
# # print(compose_method_list)
|
186
|
+
|
187
|
+
# compose_method_list_pop = deepcopy(compose_method_list)
|
188
|
+
# if len(compose_method_list_pop) > 1:
|
189
|
+
# compose_method = compose_method_list_pop.pop()
|
190
|
+
|
191
|
+
# if num_dims > (target_dimension) and num_dims != 0:
|
192
|
+
# selected_dim = dims[-1]
|
193
|
+
# outer_container = ComposableContainerVideo()
|
194
|
+
# for i in range(dataset.sizes[selected_dim]):
|
195
|
+
# sliced = dataset.isel({selected_dim: i})
|
196
|
+
# label_val = sliced.coords[selected_dim].values.item()
|
197
|
+
# inner_container = ComposableContainerVideo()
|
198
|
+
|
199
|
+
# panes = self._to_video_panes_ds(
|
200
|
+
# sliced,
|
201
|
+
# plot_callback=plot_callback,
|
202
|
+
# target_dimension=target_dimension,
|
203
|
+
# compose_method_list=compose_method_list_pop,
|
204
|
+
# result_var=result_var,
|
205
|
+
# root_dimensions=root_dimensions,
|
206
|
+
# time_sequence_dimension=time_sequence_dimension,
|
207
|
+
# )
|
208
|
+
# inner_container.append(panes)
|
209
|
+
|
210
|
+
# rendered = inner_container.render(
|
211
|
+
# RenderCfg(
|
212
|
+
# var_name=selected_dim,
|
213
|
+
# var_value=label_val,
|
214
|
+
# compose_method=compose_method,
|
215
|
+
# duration=target_duration,
|
216
|
+
# )
|
217
|
+
# )
|
218
|
+
# outer_container.append(rendered)
|
219
|
+
# return outer_container.render(
|
220
|
+
# RenderCfg(
|
221
|
+
# compose_method=compose_method,
|
222
|
+
# duration=target_duration,
|
223
|
+
# background_col=color_tuple_to_255(int_to_col(num_dims - 2, 0.05, 1.0)),
|
224
|
+
# # background_col= (255,0,0),
|
225
|
+
# )
|
226
|
+
# )
|
227
|
+
# return plot_callback(dataset=dataset, result_var=result_var, **kwargs)
|
@@ -140,7 +140,7 @@ class HoloviewResult(PanelResult):
|
|
140
140
|
elif not isinstance(tap_var, list):
|
141
141
|
tap_var = [tap_var]
|
142
142
|
|
143
|
-
if len(tap_var) == 0 or self.plt_cnt_cfg.inputs_cnt > 1:
|
143
|
+
if len(tap_var) == 0 or self.plt_cnt_cfg.inputs_cnt > 1 or not use_tap:
|
144
144
|
heatmap_cb = self.to_line_ds
|
145
145
|
else:
|
146
146
|
heatmap_cb = partial(
|
@@ -200,6 +200,7 @@ class HoloviewResult(PanelResult):
|
|
200
200
|
result_var: Parameter = None,
|
201
201
|
tap_var=None,
|
202
202
|
tap_container: pn.pane.panel = None,
|
203
|
+
tap_container_direction: pn.Column | pn.Row = None,
|
203
204
|
target_dimension=2,
|
204
205
|
**kwargs,
|
205
206
|
) -> Optional[pn.panel]:
|
@@ -208,11 +209,14 @@ class HoloviewResult(PanelResult):
|
|
208
209
|
elif not isinstance(tap_var, list):
|
209
210
|
tap_var = [tap_var]
|
210
211
|
|
211
|
-
if len(tap_var) == 0:
|
212
|
+
if len(tap_var) == 0 or not use_tap:
|
212
213
|
heatmap_cb = self.to_heatmap_ds
|
213
214
|
else:
|
214
215
|
heatmap_cb = partial(
|
215
|
-
self.to_heatmap_container_tap_ds,
|
216
|
+
self.to_heatmap_container_tap_ds,
|
217
|
+
result_var_plots=tap_var,
|
218
|
+
container=tap_container,
|
219
|
+
tap_container_direction=tap_container_direction,
|
216
220
|
)
|
217
221
|
|
218
222
|
return self.filter(
|
@@ -251,7 +255,7 @@ class HoloviewResult(PanelResult):
|
|
251
255
|
else:
|
252
256
|
containers = listify(container)
|
253
257
|
|
254
|
-
cont_instances = [c(**kwargs) for c in containers]
|
258
|
+
cont_instances = [c(**kwargs) if c is not None else None for c in containers]
|
255
259
|
return result_var_plots, cont_instances
|
256
260
|
|
257
261
|
def to_heatmap_container_tap_ds(
|
@@ -260,6 +264,7 @@ class HoloviewResult(PanelResult):
|
|
260
264
|
result_var: Parameter,
|
261
265
|
result_var_plots: List[Parameter] = None,
|
262
266
|
container: pn.pane.panel = None,
|
267
|
+
tap_container_direction: pn.Column | pn.Row = None,
|
263
268
|
**kwargs,
|
264
269
|
) -> pn.Row:
|
265
270
|
htmap = self.to_heatmap_ds(dataset, result_var).opts(tools=["hover"], **kwargs)
|
@@ -322,8 +327,11 @@ class HoloviewResult(PanelResult):
|
|
322
327
|
ls = hv.streams.MouseLeave(source=htmap)
|
323
328
|
ls.add_subscriber(on_exit)
|
324
329
|
|
325
|
-
|
326
|
-
|
330
|
+
if tap_container_direction is None:
|
331
|
+
tap_container_direction = pn.Column
|
332
|
+
bound_plot = tap_container_direction(*cont_instances)
|
333
|
+
|
334
|
+
return pn.Row(htmap, pn.Column(title, bound_plot))
|
327
335
|
|
328
336
|
def to_line_tap_ds(
|
329
337
|
self,
|
@@ -677,7 +685,7 @@ class HoloviewResult(PanelResult):
|
|
677
685
|
try:
|
678
686
|
surface = hvds.to(hv.Surface, vdims=[result_var.name])
|
679
687
|
surface = surface.opts(colorbar=True)
|
680
|
-
except Exception as e:
|
688
|
+
except Exception as e: # pylint: disable=broad-except
|
681
689
|
logging.warning(e)
|
682
690
|
|
683
691
|
if self.bench_cfg.repeats > 1:
|
bencher/results/optuna_result.py
CHANGED
@@ -63,6 +63,7 @@ class OptunaResult:
|
|
63
63
|
self.studies = []
|
64
64
|
self.plt_cnt_cfg = PltCntCfg()
|
65
65
|
self.plot_inputs = []
|
66
|
+
self.dataset_list = []
|
66
67
|
|
67
68
|
# self.width=600/
|
68
69
|
# self.height=600
|
@@ -177,7 +178,7 @@ class OptunaResult:
|
|
177
178
|
df = self.to_pandas()
|
178
179
|
all_vars = []
|
179
180
|
for v in self.bench_cfg.all_vars:
|
180
|
-
if type(v)
|
181
|
+
if type(v) is not TimeEvent:
|
181
182
|
all_vars.append(v)
|
182
183
|
|
183
184
|
print("All vars", all_vars)
|
@@ -202,8 +203,8 @@ class OptunaResult:
|
|
202
203
|
params = {}
|
203
204
|
values = []
|
204
205
|
for i in all_vars:
|
205
|
-
if type(i)
|
206
|
-
if type(row[1][i.name])
|
206
|
+
if type(i) is TimeSnapshot:
|
207
|
+
if type(row[1][i.name]) is np.datetime64:
|
207
208
|
params[i.name] = row[1][i.name].timestamp()
|
208
209
|
else:
|
209
210
|
params[i.name] = row[1][i.name]
|
bencher/results/panel_result.py
CHANGED
bencher/results/video_summary.py
CHANGED
@@ -1,94 +1,44 @@
|
|
1
|
-
from bencher.utils import params_to_str
|
2
1
|
from typing import Optional, List
|
3
|
-
import
|
2
|
+
from copy import deepcopy
|
4
3
|
import panel as pn
|
5
4
|
import xarray as xr
|
6
5
|
from param import Parameter
|
7
6
|
from bencher.results.bench_result_base import BenchResultBase, ReduceType
|
8
7
|
from bencher.variables.results import ResultImage
|
9
8
|
from bencher.plotting.plot_filter import VarRange, PlotFilter
|
10
|
-
from bencher.utils import callable_name,
|
9
|
+
from bencher.utils import callable_name, int_to_col, color_tuple_to_255
|
11
10
|
from bencher.video_writer import VideoWriter
|
12
|
-
from bencher.results.float_formatter import FormatFloat
|
13
11
|
from bencher.results.video_result import VideoControls
|
14
|
-
from bencher.
|
15
|
-
|
12
|
+
from bencher.results.composable_container.composable_container_video import (
|
13
|
+
ComposableContainerVideo,
|
14
|
+
ComposeType,
|
15
|
+
RenderCfg,
|
16
|
+
)
|
16
17
|
|
17
18
|
|
18
19
|
class VideoSummaryResult(BenchResultBase):
|
19
20
|
def to_video_summary(
|
20
21
|
self,
|
21
22
|
result_var: Parameter = None,
|
22
|
-
input_order: List[str] = None,
|
23
23
|
reverse: bool = True,
|
24
24
|
result_types=(ResultImage,),
|
25
25
|
**kwargs,
|
26
26
|
) -> Optional[pn.panel]:
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
self.plt_cnt_cfg, callable_name(self.to_video_summary_ds)
|
27
|
+
return self.to_video_grid(
|
28
|
+
result_var=result_var,
|
29
|
+
result_types=result_types,
|
30
|
+
time_sequence_dimension=-1,
|
31
|
+
reverse=reverse,
|
32
|
+
**kwargs,
|
34
33
|
)
|
35
34
|
|
36
|
-
# video_controls = VideoControls()
|
37
|
-
if matches_res.overall:
|
38
|
-
ds = self.to_dataset(ReduceType.SQUEEZE)
|
39
|
-
row = pn.Row()
|
40
|
-
for rv in self.get_results_var_list(result_var):
|
41
|
-
if isinstance(rv, result_types):
|
42
|
-
row.append(self.to_video_summary_ds(ds, rv, input_order, reverse, **kwargs))
|
43
|
-
return row
|
44
|
-
return matches_res.to_panel()
|
45
|
-
|
46
|
-
def to_video_summary_ds(
|
47
|
-
self,
|
48
|
-
dataset: xr.Dataset,
|
49
|
-
result_var: Parameter,
|
50
|
-
input_order: List[str] = None,
|
51
|
-
reverse: bool = True,
|
52
|
-
video_controls: VideoControls = None,
|
53
|
-
**kwargs,
|
54
|
-
):
|
55
|
-
vr = VideoWriter()
|
56
|
-
da = dataset[result_var.name]
|
57
|
-
|
58
|
-
if input_order is None:
|
59
|
-
input_order = list(da.dims)
|
60
|
-
else:
|
61
|
-
input_order = params_to_str(input_order)
|
62
|
-
if reverse:
|
63
|
-
input_order = list(reversed(input_order))
|
64
|
-
|
65
|
-
inputs_produc = [da.coords[i].values for i in input_order]
|
66
|
-
|
67
|
-
for index in itertools.product(*inputs_produc):
|
68
|
-
lookup = dict(zip(input_order, index))
|
69
|
-
val = da.loc[lookup].item()
|
70
|
-
index = listify(index)
|
71
|
-
for i in range(len(index)):
|
72
|
-
if isinstance(index[i], (int, float)):
|
73
|
-
index[i] = FormatFloat()(index[i])
|
74
|
-
label = ", ".join(f"{a[0]}={a[1]}" for a in list(zip(input_order, index)))
|
75
|
-
if val is not None:
|
76
|
-
vr.append_file(val, label)
|
77
|
-
fn = vr.write_png(**kwargs)
|
78
|
-
kwargs.pop("target_duration", None)
|
79
|
-
if fn is not None:
|
80
|
-
if video_controls is None:
|
81
|
-
video_controls = VideoControls()
|
82
|
-
vid = video_controls.video_container(fn, **kwargs)
|
83
|
-
return vid
|
84
|
-
|
85
|
-
return None
|
86
|
-
|
87
35
|
def to_video_grid(
|
88
36
|
self,
|
89
37
|
result_var: Parameter = None,
|
90
38
|
result_types=(ResultImage,),
|
91
39
|
pane_collection: pn.pane = None,
|
40
|
+
time_sequence_dimension=0,
|
41
|
+
target_duration: float = None,
|
92
42
|
**kwargs,
|
93
43
|
) -> Optional[pn.panel]:
|
94
44
|
"""Returns the results compiled into a video
|
@@ -118,7 +68,15 @@ class VideoSummaryResult(BenchResultBase):
|
|
118
68
|
ds = self.to_dataset(ReduceType.SQUEEZE)
|
119
69
|
for rv in self.get_results_var_list(result_var):
|
120
70
|
if isinstance(rv, result_types):
|
121
|
-
pane_collection.append(
|
71
|
+
pane_collection.append(
|
72
|
+
self.to_video_grid_ds(
|
73
|
+
ds,
|
74
|
+
rv,
|
75
|
+
time_sequence_dimension=time_sequence_dimension,
|
76
|
+
target_duration=target_duration,
|
77
|
+
**kwargs,
|
78
|
+
)
|
79
|
+
)
|
122
80
|
return pane_collection
|
123
81
|
return matches_res.to_panel()
|
124
82
|
|
@@ -127,17 +85,18 @@ class VideoSummaryResult(BenchResultBase):
|
|
127
85
|
dataset: xr.Dataset,
|
128
86
|
result_var: Parameter,
|
129
87
|
reverse=True,
|
88
|
+
time_sequence_dimension=0,
|
130
89
|
video_controls: VideoControls = None,
|
131
90
|
target_duration: float = None,
|
132
91
|
**kwargs,
|
133
92
|
):
|
134
|
-
vr = VideoWriter()
|
135
|
-
|
136
93
|
cvc = self._to_video_panes_ds(
|
137
94
|
dataset,
|
138
95
|
self.plot_cb,
|
139
96
|
target_dimension=0,
|
140
97
|
horizontal=True,
|
98
|
+
compose_method=ComposeType.right,
|
99
|
+
time_sequence_dimension=time_sequence_dimension,
|
141
100
|
result_var=result_var,
|
142
101
|
final=True,
|
143
102
|
reverse=reverse,
|
@@ -145,27 +104,62 @@ class VideoSummaryResult(BenchResultBase):
|
|
145
104
|
**kwargs,
|
146
105
|
)
|
147
106
|
|
148
|
-
|
107
|
+
filename = VideoWriter().write_video_raw(cvc)
|
149
108
|
|
150
|
-
if
|
109
|
+
if filename is not None:
|
151
110
|
if video_controls is None:
|
152
111
|
video_controls = VideoControls()
|
153
|
-
|
154
|
-
|
112
|
+
return video_controls.video_container(
|
113
|
+
filename, width=kwargs.get("width", None), height=kwargs.get("height", None)
|
114
|
+
)
|
155
115
|
return None
|
156
116
|
|
157
117
|
def plot_cb(self, dataset, result_var, **kwargs):
|
158
118
|
val = self.ds_to_container(dataset, result_var, container=None, **kwargs)
|
159
119
|
return val
|
160
120
|
|
121
|
+
def dataset_to_compose_list(
|
122
|
+
self,
|
123
|
+
dataset: xr.Dataset,
|
124
|
+
first_compose_method: ComposeType = ComposeType.down,
|
125
|
+
time_sequence_dimension: int = 0,
|
126
|
+
) -> List[ComposeType]:
|
127
|
+
""" "Given a dataset, chose an order for composing the results. By default will flip between right and down and the last dimension will be a time sequence.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
dataset (xr.Dataset): the dataset to render
|
131
|
+
first_compose_method (ComposeType, optional): the direction of the first composition method. Defaults to ComposeType.right.
|
132
|
+
time_sequence_dimension (int, optional): The dimension to start time sequencing instead of composing in space. Defaults to 0.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
List[ComposeType]: A list of composition methods for composing the dataset result
|
136
|
+
"""
|
137
|
+
|
138
|
+
num_dims = len(dataset.sizes)
|
139
|
+
if time_sequence_dimension == -1: # use time sequence for everything
|
140
|
+
compose_method_list = [ComposeType.sequence] * (num_dims + 1)
|
141
|
+
else:
|
142
|
+
compose_method_list = [first_compose_method]
|
143
|
+
compose_method_list.extend(
|
144
|
+
ComposeType.flip(compose_method_list[-1]) for _ in range(num_dims - 1)
|
145
|
+
)
|
146
|
+
compose_method_list.append(ComposeType.sequence)
|
147
|
+
|
148
|
+
for i in range(min(len(compose_method_list), time_sequence_dimension + 1)):
|
149
|
+
compose_method_list[i] = ComposeType.sequence
|
150
|
+
|
151
|
+
return compose_method_list
|
152
|
+
|
161
153
|
def _to_video_panes_ds(
|
162
154
|
self,
|
163
155
|
dataset: xr.Dataset,
|
164
156
|
plot_callback: callable = None,
|
165
157
|
target_dimension=0,
|
166
|
-
|
158
|
+
compose_method=ComposeType.right,
|
159
|
+
compose_method_list=None,
|
167
160
|
result_var=None,
|
168
|
-
|
161
|
+
time_sequence_dimension=0,
|
162
|
+
root_dimensions=None,
|
169
163
|
reverse=False,
|
170
164
|
target_duration: float = None,
|
171
165
|
**kwargs,
|
@@ -175,43 +169,54 @@ class VideoSummaryResult(BenchResultBase):
|
|
175
169
|
if reverse:
|
176
170
|
dims = list(reversed(dims))
|
177
171
|
|
172
|
+
if root_dimensions is None:
|
173
|
+
root_dimensions = num_dims
|
174
|
+
|
175
|
+
if compose_method_list is None:
|
176
|
+
compose_method_list = self.dataset_to_compose_list(
|
177
|
+
dataset, compose_method, time_sequence_dimension=time_sequence_dimension
|
178
|
+
)
|
179
|
+
|
180
|
+
# print(compose_method_list)
|
181
|
+
|
182
|
+
compose_method_list_pop = deepcopy(compose_method_list)
|
183
|
+
if len(compose_method_list_pop) > 1:
|
184
|
+
compose_method = compose_method_list_pop.pop()
|
185
|
+
|
178
186
|
if num_dims > (target_dimension) and num_dims != 0:
|
179
187
|
selected_dim = dims[-1]
|
180
|
-
|
181
|
-
dim_color = int_to_col(num_dims - 2, 0.05, 1.0)
|
182
|
-
# sliced = dataset.isel({selected_dim: i})
|
183
|
-
# label_val = sliced.coords[selected_dim].values.item()
|
184
|
-
|
185
|
-
outer_container = ComposableContainerVideo(
|
186
|
-
name=" vs ".join(dims),
|
187
|
-
background_col=dim_color,
|
188
|
-
horizontal=horizontal,
|
189
|
-
target_duration=target_duration,
|
190
|
-
# var_name=selected_dim,
|
191
|
-
# var_value=label_val,
|
192
|
-
)
|
193
|
-
max_len = 0
|
188
|
+
outer_container = ComposableContainerVideo()
|
194
189
|
for i in range(dataset.sizes[selected_dim]):
|
195
190
|
sliced = dataset.isel({selected_dim: i})
|
196
191
|
label_val = sliced.coords[selected_dim].values.item()
|
197
|
-
inner_container = ComposableContainerVideo(
|
198
|
-
|
199
|
-
var_name=selected_dim,
|
200
|
-
var_value=label_val,
|
201
|
-
horizontal=horizontal,
|
202
|
-
target_duration=target_duration,
|
203
|
-
)
|
192
|
+
inner_container = ComposableContainerVideo()
|
193
|
+
|
204
194
|
panes = self._to_video_panes_ds(
|
205
195
|
sliced,
|
206
196
|
plot_callback=plot_callback,
|
207
197
|
target_dimension=target_dimension,
|
208
|
-
|
198
|
+
compose_method_list=compose_method_list_pop,
|
209
199
|
result_var=result_var,
|
200
|
+
root_dimensions=root_dimensions,
|
201
|
+
time_sequence_dimension=time_sequence_dimension,
|
210
202
|
)
|
211
203
|
inner_container.append(panes)
|
212
204
|
|
213
|
-
|
214
|
-
|
205
|
+
rendered = inner_container.render(
|
206
|
+
RenderCfg(
|
207
|
+
var_name=selected_dim,
|
208
|
+
var_value=label_val,
|
209
|
+
compose_method=compose_method,
|
210
|
+
duration=target_duration,
|
211
|
+
)
|
212
|
+
)
|
215
213
|
outer_container.append(rendered)
|
216
|
-
return outer_container.render(
|
214
|
+
return outer_container.render(
|
215
|
+
RenderCfg(
|
216
|
+
compose_method=compose_method,
|
217
|
+
duration=target_duration,
|
218
|
+
background_col=color_tuple_to_255(int_to_col(num_dims - 2, 0.05, 1.0)),
|
219
|
+
# background_col= (255,0,0),
|
220
|
+
)
|
221
|
+
)
|
217
222
|
return plot_callback(dataset=dataset, result_var=result_var, **kwargs)
|
bencher/utils.py
CHANGED
@@ -8,8 +8,9 @@ from colorsys import hsv_to_rgb
|
|
8
8
|
from pathlib import Path
|
9
9
|
from uuid import uuid4
|
10
10
|
from functools import partial
|
11
|
-
from typing import Callable, Any, List
|
11
|
+
from typing import Callable, Any, List, Tuple
|
12
12
|
import param
|
13
|
+
import numpy as np
|
13
14
|
|
14
15
|
|
15
16
|
def hmap_canonical_input(dic: dict) -> tuple:
|
@@ -98,6 +99,23 @@ def un_camel(camel: str) -> str:
|
|
98
99
|
return capitalise_words(re.sub("([a-z])([A-Z])", r"\g<1> \g<2>", camel.replace("_", " ")))
|
99
100
|
|
100
101
|
|
102
|
+
def mult_tuple(inp: Tuple[float], val: float) -> Tuple[float]:
|
103
|
+
return tuple(np.array(inp) * val)
|
104
|
+
|
105
|
+
|
106
|
+
def tabs_in_markdown(regular_str: str, spaces: int = 2) -> str:
|
107
|
+
"""Given a string with tabs in the form \t convert the to   which is a double space in markdown
|
108
|
+
|
109
|
+
Args:
|
110
|
+
regular_str (str): A string with tabs in it
|
111
|
+
spaces (int): the number of spaces per tab
|
112
|
+
|
113
|
+
Returns:
|
114
|
+
str: A string with sets of to represent the tabs in markdown
|
115
|
+
"""
|
116
|
+
return regular_str.replace("\t", "".join([" "] * spaces))
|
117
|
+
|
118
|
+
|
101
119
|
def int_to_col(int_val, sat=0.5, val=0.95, alpha=-1) -> tuple[float, float, float]:
|
102
120
|
"""Uses the golden angle to generate colors programmatically with minimum overlap between colors.
|
103
121
|
https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
@@ -129,13 +147,21 @@ def color_tuple_to_css(color: tuple[float, float, float]) -> str:
|
|
129
147
|
return f"rgb{(color[0] * 255, color[1] * 255, color[2] * 255)}"
|
130
148
|
|
131
149
|
|
150
|
+
def color_tuple_to_255(color: tuple[float, float, float]) -> tuple[float, float, float]:
|
151
|
+
return (
|
152
|
+
min(int(color[0] * 255), 255),
|
153
|
+
min(int(color[1] * 255), 255),
|
154
|
+
min(int(color[2] * 255), 255),
|
155
|
+
)
|
156
|
+
|
157
|
+
|
132
158
|
def gen_path(filename, folder="generic", suffix=".dat"):
|
133
159
|
path = Path(f"cachedir/{folder}/{filename}/")
|
134
160
|
path.mkdir(parents=True, exist_ok=True)
|
135
161
|
return f"{path.absolute().as_posix()}/{filename}_{uuid4()}{suffix}"
|
136
162
|
|
137
163
|
|
138
|
-
def gen_video_path(video_name: str = "vid", extension: str = ".
|
164
|
+
def gen_video_path(video_name: str = "vid", extension: str = ".mp4") -> str:
|
139
165
|
return gen_path(video_name, "vid", extension)
|
140
166
|
|
141
167
|
|
File without changes
|