holobench 1.25.1__py3-none-any.whl → 1.26.3__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.
Files changed (81) hide show
  1. bencher/example/benchmark_data.py +196 -0
  2. bencher/example/example_all.py +45 -0
  3. bencher/example/example_categorical.py +99 -0
  4. bencher/example/example_composable_container.py +106 -0
  5. bencher/example/example_composable_container2.py +160 -0
  6. bencher/example/example_consts.py +39 -0
  7. bencher/example/example_custom_sweep.py +59 -0
  8. bencher/example/example_custom_sweep2.py +42 -0
  9. bencher/example/example_docs.py +34 -0
  10. bencher/example/example_filepath.py +27 -0
  11. bencher/example/example_float3D.py +101 -0
  12. bencher/example/example_float_cat.py +99 -0
  13. bencher/example/example_floats.py +89 -0
  14. bencher/example/example_floats2D.py +93 -0
  15. bencher/example/example_holosweep.py +98 -0
  16. bencher/example/example_holosweep_objects.py +111 -0
  17. bencher/example/example_holosweep_tap.py +144 -0
  18. bencher/example/example_image.py +155 -0
  19. bencher/example/example_levels.py +181 -0
  20. bencher/example/example_levels2.py +37 -0
  21. bencher/example/example_pareto.py +53 -0
  22. bencher/example/example_sample_cache.py +85 -0
  23. bencher/example/example_sample_cache_context.py +116 -0
  24. bencher/example/example_simple.py +134 -0
  25. bencher/example/example_simple_bool.py +35 -0
  26. bencher/example/example_simple_cat.py +48 -0
  27. bencher/example/example_simple_float.py +28 -0
  28. bencher/example/example_simple_float2d.py +29 -0
  29. bencher/example/example_strings.py +47 -0
  30. bencher/example/example_time_event.py +63 -0
  31. bencher/example/example_video.py +118 -0
  32. bencher/example/example_workflow.py +189 -0
  33. bencher/example/experimental/example_bokeh_plotly.py +38 -0
  34. bencher/example/experimental/example_hover_ex.py +45 -0
  35. bencher/example/experimental/example_hvplot_explorer.py +39 -0
  36. bencher/example/experimental/example_interactive.py +75 -0
  37. bencher/example/experimental/example_streamnd.py +49 -0
  38. bencher/example/experimental/example_streams.py +36 -0
  39. bencher/example/experimental/example_template.py +40 -0
  40. bencher/example/experimental/example_updates.py +84 -0
  41. bencher/example/experimental/example_vector.py +84 -0
  42. bencher/example/meta/example_meta.py +171 -0
  43. bencher/example/meta/example_meta_cat.py +25 -0
  44. bencher/example/meta/example_meta_float.py +23 -0
  45. bencher/example/meta/example_meta_levels.py +26 -0
  46. bencher/example/optuna/example_optuna.py +78 -0
  47. bencher/example/shelved/example_float2D_scatter.py +109 -0
  48. bencher/example/shelved/example_float3D_cone.py +96 -0
  49. bencher/example/shelved/example_kwargs.py +63 -0
  50. bencher/plotting/__init__.py +0 -0
  51. bencher/plotting/plot_filter.py +110 -0
  52. bencher/plotting/plt_cnt_cfg.py +75 -0
  53. bencher/results/__init__.py +0 -0
  54. bencher/results/bench_result.py +94 -0
  55. bencher/results/bench_result_base.py +476 -0
  56. bencher/results/composable_container/__init__.py +0 -0
  57. bencher/results/composable_container/composable_container_base.py +73 -0
  58. bencher/results/composable_container/composable_container_panel.py +39 -0
  59. bencher/results/composable_container/composable_container_video.py +184 -0
  60. bencher/results/float_formatter.py +44 -0
  61. bencher/results/holoview_result.py +753 -0
  62. bencher/results/optuna_result.py +354 -0
  63. bencher/results/panel_result.py +41 -0
  64. bencher/results/plotly_result.py +65 -0
  65. bencher/results/video_result.py +38 -0
  66. bencher/results/video_summary.py +222 -0
  67. bencher/variables/__init__.py +0 -0
  68. bencher/variables/inputs.py +202 -0
  69. bencher/variables/parametrised_sweep.py +208 -0
  70. bencher/variables/results.py +214 -0
  71. bencher/variables/sweep_base.py +162 -0
  72. bencher/variables/time.py +92 -0
  73. holobench-1.26.3.data/data/share/ament_index/resource_index/packages/bencher +0 -0
  74. {holobench-1.25.1.dist-info → holobench-1.26.3.dist-info}/METADATA +5 -7
  75. holobench-1.26.3.dist-info/RECORD +93 -0
  76. holobench-1.25.1.dist-info/RECORD +0 -20
  77. /holobench-1.25.1.data/data/share/ament_index/resource_index/packages/bencher → /bencher/example/__init__.py +0 -0
  78. {holobench-1.25.1.data → holobench-1.26.3.data}/data/share/bencher/package.xml +0 -0
  79. {holobench-1.25.1.dist-info → holobench-1.26.3.dist-info}/LICENSE +0 -0
  80. {holobench-1.25.1.dist-info → holobench-1.26.3.dist-info}/WHEEL +0 -0
  81. {holobench-1.25.1.dist-info → holobench-1.26.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,753 @@
1
+ from __future__ import annotations
2
+ import logging
3
+ from typing import List, Optional
4
+ import panel as pn
5
+ import holoviews as hv
6
+ from param import Parameter
7
+ from functools import partial
8
+ import hvplot.xarray # noqa pylint: disable=duplicate-code,unused-import
9
+ import xarray as xr
10
+
11
+ from bencher.utils import hmap_canonical_input, get_nearest_coords, get_nearest_coords1D, listify
12
+ from bencher.results.panel_result import PanelResult
13
+ from bencher.results.bench_result_base import ReduceType
14
+
15
+ from bencher.plotting.plot_filter import PlotFilter, VarRange
16
+ from bencher.variables.results import ResultVar, ResultImage, ResultVideo
17
+
18
+ hv.extension("bokeh", "plotly")
19
+
20
+ # Flag to enable or disable tap tool functionality in visualizations
21
+ use_tap = True
22
+
23
+
24
+ class HoloviewResult(PanelResult):
25
+ @staticmethod
26
+ def set_default_opts(width=600, height=600):
27
+ width_heigh = {"width": width, "height": height, "tools": ["hover"]}
28
+ hv.opts.defaults(
29
+ hv.opts.Curve(**width_heigh),
30
+ hv.opts.Points(**width_heigh),
31
+ hv.opts.Bars(**width_heigh),
32
+ hv.opts.Scatter(**width_heigh),
33
+ hv.opts.HeatMap(cmap="plasma", **width_heigh, colorbar=True),
34
+ # hv.opts.Surface(**width_heigh),
35
+ hv.opts.GridSpace(plot_size=400),
36
+ )
37
+ return width_heigh
38
+
39
+ def to(self, hv_type: hv.Chart, reduce: ReduceType = ReduceType.AUTO, **kwargs) -> hv.Chart:
40
+ return self.to_hv_dataset(reduce).to(hv_type, **kwargs)
41
+
42
+ def overlay_plots(self, plot_callback: callable) -> Optional[hv.Overlay]:
43
+ results = []
44
+ markdown_results = pn.Row()
45
+ for rv in self.bench_cfg.result_vars:
46
+ res = plot_callback(rv)
47
+ if res is not None:
48
+ if isinstance(res, pn.pane.Markdown):
49
+ markdown_results.append(res)
50
+ else:
51
+ results.append(res)
52
+ if len(results) > 0:
53
+ overlay = hv.Overlay(results).collate()
54
+ if len(markdown_results) == 0:
55
+ return overlay
56
+ return pn.Row(overlay, markdown_results)
57
+ if len(markdown_results) > 0:
58
+ return markdown_results
59
+ return None
60
+
61
+ def layout_plots(self, plot_callback: callable):
62
+ if len(self.bench_cfg.result_vars) > 0:
63
+ pt = hv.Layout()
64
+ got_results = False
65
+ for rv in self.bench_cfg.result_vars:
66
+ res = plot_callback(rv)
67
+ if res is not None:
68
+ got_results = True
69
+ pt += plot_callback(rv)
70
+ return pt if got_results else None
71
+ return plot_callback(self.bench_cfg.result_vars[0])
72
+
73
+ def time_widget(self, title):
74
+ return {"title": title}
75
+ # if self.bench_cfg.over_time:
76
+ # time_widget_args = {"widget_type": "scrubber", "widget_location": "bottom"}
77
+ # time_widget_args["title"] = None # use the title generated by the widget instead
78
+ # else:
79
+ # time_widget_args = {"widget_type": "individual"}
80
+ # time_widget_args["title"] = title
81
+
82
+ # return time_widget_args
83
+
84
+ def to_bar(self, result_var: Parameter = None, **kwargs) -> Optional[pn.panel]:
85
+ return self.filter(
86
+ self.to_bar_ds,
87
+ float_range=VarRange(0, 0),
88
+ cat_range=VarRange(0, None),
89
+ repeats_range=VarRange(1, 1),
90
+ panel_range=VarRange(0, None),
91
+ reduce=ReduceType.SQUEEZE,
92
+ target_dimension=2,
93
+ result_var=result_var,
94
+ result_types=(ResultVar),
95
+ **kwargs,
96
+ )
97
+
98
+ def to_bar_ds(self, dataset: xr.Dataset, result_var: Parameter = None, **kwargs):
99
+ by = None
100
+ if self.plt_cnt_cfg.cat_cnt >= 2:
101
+ by = self.plt_cnt_cfg.cat_vars[1].name
102
+ da_plot = dataset[result_var.name]
103
+ title = self.title_from_ds(da_plot, result_var, **kwargs)
104
+ time_widget_args = self.time_widget(title)
105
+ return da_plot.hvplot.bar(by=by, **time_widget_args, **kwargs)
106
+
107
+ def hv_container_ds(
108
+ self, dataset: xr.Dataset, result_var: Parameter, container: hv.Chart = None, **kwargs
109
+ ):
110
+ return hv.Dataset(dataset[result_var.name]).to(container).opts(**kwargs)
111
+
112
+ def to_hv_container(
113
+ self,
114
+ container: pn.pane.panel,
115
+ reduce_type=ReduceType.AUTO,
116
+ target_dimension: int = 2,
117
+ result_var: Parameter = None,
118
+ result_types=(ResultVar),
119
+ **kwargs,
120
+ ) -> Optional[pn.pane.panel]:
121
+ return self.map_plot_panes(
122
+ partial(self.hv_container_ds, container=container),
123
+ hv_dataset=self.to_hv_dataset(reduce_type),
124
+ target_dimension=target_dimension,
125
+ result_var=result_var,
126
+ result_types=result_types,
127
+ **kwargs,
128
+ )
129
+
130
+ def to_line(
131
+ self,
132
+ result_var: Parameter = None,
133
+ tap_var=None,
134
+ tap_container: pn.pane.panel = None,
135
+ target_dimension=2,
136
+ **kwargs,
137
+ ) -> Optional[pn.panel]:
138
+ if tap_var is None:
139
+ tap_var = self.plt_cnt_cfg.panel_vars
140
+ elif not isinstance(tap_var, list):
141
+ tap_var = [tap_var]
142
+
143
+ if len(tap_var) == 0 or self.plt_cnt_cfg.inputs_cnt > 1 or not use_tap:
144
+ heatmap_cb = self.to_line_ds
145
+ else:
146
+ heatmap_cb = partial(
147
+ self.to_line_tap_ds, result_var_plots=tap_var, container=tap_container
148
+ )
149
+
150
+ return self.filter(
151
+ heatmap_cb,
152
+ float_range=VarRange(1, 1),
153
+ cat_range=VarRange(0, None),
154
+ repeats_range=VarRange(1, 1),
155
+ panel_range=VarRange(0, None),
156
+ reduce=ReduceType.SQUEEZE,
157
+ target_dimension=target_dimension,
158
+ result_var=result_var,
159
+ result_types=(ResultVar),
160
+ **kwargs,
161
+ )
162
+
163
+ def to_line_ds(self, dataset: xr.Dataset, result_var: Parameter, **kwargs):
164
+ x = self.plt_cnt_cfg.float_vars[0].name
165
+ by = None
166
+ if self.plt_cnt_cfg.cat_cnt >= 1:
167
+ by = self.plt_cnt_cfg.cat_vars[0].name
168
+ da_plot = dataset[result_var.name]
169
+ title = self.title_from_ds(da_plot, result_var, **kwargs)
170
+ time_widget_args = self.time_widget(title)
171
+ return da_plot.hvplot.line(x=x, by=by, **time_widget_args, **kwargs)
172
+
173
+ def to_curve(self, result_var: Parameter = None, **kwargs):
174
+ return self.filter(
175
+ self.to_curve_ds,
176
+ float_range=VarRange(1, 1),
177
+ cat_range=VarRange(0, None),
178
+ repeats_range=VarRange(2, None),
179
+ reduce=ReduceType.REDUCE,
180
+ target_dimension=2,
181
+ result_var=result_var,
182
+ result_types=(ResultVar),
183
+ **kwargs,
184
+ )
185
+
186
+ def to_curve_ds(
187
+ self, dataset: xr.Dataset, result_var: Parameter, **kwargs
188
+ ) -> Optional[hv.Curve]:
189
+ hvds = hv.Dataset(dataset)
190
+ # result_var = self.get_results_var_list(result_var)[0]
191
+ title = self.title_from_ds(dataset, result_var, **kwargs)
192
+ pt = hvds.to(hv.Curve).opts(title=title, **kwargs)
193
+ pt *= hvds.to(hv.Spread).opts(alpha=0.2)
194
+ if len(dataset.sizes) > 1:
195
+ return pt.opts(legend_position="right").overlay()
196
+ return pt.opts(legend_position="right")
197
+
198
+ def to_heatmap(
199
+ self,
200
+ result_var: Parameter = None,
201
+ tap_var=None,
202
+ tap_container: pn.pane.panel = None,
203
+ tap_container_direction: pn.Column | pn.Row = None,
204
+ target_dimension=2,
205
+ **kwargs,
206
+ ) -> Optional[pn.panel]:
207
+ if tap_var is None:
208
+ tap_var = self.plt_cnt_cfg.panel_vars
209
+ elif not isinstance(tap_var, list):
210
+ tap_var = [tap_var]
211
+
212
+ if len(tap_var) == 0 or not use_tap:
213
+ heatmap_cb = self.to_heatmap_ds
214
+ else:
215
+ heatmap_cb = partial(
216
+ self.to_heatmap_container_tap_ds,
217
+ result_var_plots=tap_var,
218
+ container=tap_container,
219
+ tap_container_direction=tap_container_direction,
220
+ )
221
+
222
+ return self.filter(
223
+ heatmap_cb,
224
+ float_range=VarRange(0, None),
225
+ cat_range=VarRange(0, None),
226
+ input_range=VarRange(2, None),
227
+ panel_range=VarRange(0, None),
228
+ target_dimension=target_dimension,
229
+ result_var=result_var,
230
+ result_types=(ResultVar),
231
+ **kwargs,
232
+ )
233
+
234
+ def to_heatmap_ds(
235
+ self, dataset: xr.Dataset, result_var: Parameter, **kwargs
236
+ ) -> Optional[hv.HeatMap]:
237
+ if len(dataset.dims) >= 2:
238
+ x = self.bench_cfg.input_vars[0].name
239
+ y = self.bench_cfg.input_vars[1].name
240
+ C = result_var.name
241
+ title = f"Heatmap of {result_var.name}"
242
+ time_args = self.time_widget(title)
243
+ return dataset.hvplot.heatmap(x=x, y=y, C=C, cmap="plasma", **time_args, **kwargs)
244
+ return None
245
+
246
+ def result_var_to_container(self, result_var):
247
+ if isinstance(result_var, ResultImage):
248
+ return pn.pane.PNG
249
+ return pn.pane.Video if isinstance(result_var, ResultVideo) else pn.Column
250
+
251
+ def setup_results_and_containers(self, result_var_plots, container, **kwargs):
252
+ result_var_plots = listify(result_var_plots)
253
+ if container is None:
254
+ containers = [self.result_var_to_container(rv) for rv in result_var_plots]
255
+ else:
256
+ containers = listify(container)
257
+
258
+ cont_instances = [c(**kwargs) if c is not None else None for c in containers]
259
+ return result_var_plots, cont_instances
260
+
261
+ def to_heatmap_container_tap_ds(
262
+ self,
263
+ dataset: xr.Dataset,
264
+ result_var: Parameter,
265
+ result_var_plots: List[Parameter] = None,
266
+ container: pn.pane.panel = None,
267
+ tap_container_direction: pn.Column | pn.Row = None,
268
+ **kwargs,
269
+ ) -> pn.Row:
270
+ htmap = self.to_heatmap_ds(dataset, result_var).opts(tools=["hover"], **kwargs)
271
+ result_var_plots, cont_instances = self.setup_results_and_containers(
272
+ result_var_plots, container
273
+ )
274
+ title = pn.pane.Markdown("Selected: None")
275
+
276
+ state = dict(x=None, y=None, update=False)
277
+
278
+ def tap_plot_heatmap(x, y): # pragma: no cover
279
+ # print(f"moved {x}{y}")
280
+ x_nearest_new = get_nearest_coords1D(
281
+ x, dataset.coords[self.bench_cfg.input_vars[0].name].data
282
+ )
283
+ y_nearest_new = get_nearest_coords1D(
284
+ y, dataset.coords[self.bench_cfg.input_vars[1].name].data
285
+ )
286
+
287
+ # xv = self.bench_cfg.input_vars[0].name
288
+ # yv = self.bench_cfg.input_vars[1].name
289
+ # nearest = get_nearest_coords(dataset, **{xv: x, yv: y})
290
+ # print(nearest)
291
+ # print(x_nearest_new,y_nearest_new)
292
+
293
+ if x_nearest_new != state["x"]:
294
+ state["x"] = x_nearest_new
295
+ state["update"] = True
296
+ if y_nearest_new != state["y"]:
297
+ state["y"] = y_nearest_new
298
+ state["update"] = True
299
+
300
+ if state["update"]:
301
+ kdims = {}
302
+ kdims[self.bench_cfg.input_vars[0].name] = state["x"]
303
+ kdims[self.bench_cfg.input_vars[1].name] = state["y"]
304
+
305
+ if hasattr(htmap, "current_key"):
306
+ for d, k in zip(htmap.kdims, htmap.current_key):
307
+ kdims[d.name] = k
308
+ for rv, cont in zip(result_var_plots, cont_instances):
309
+ ds = dataset[rv.name]
310
+ val = ds.sel(**kdims)
311
+ item = self.zero_dim_da_to_val(val)
312
+ title.object = "Selected: " + ", ".join([f"{k}:{v}" for k, v in kdims.items()])
313
+
314
+ cont.object = item
315
+ if hasattr(cont, "autoplay"): # container is a video, set to autoplay
316
+ cont.paused = False
317
+ cont.time = 0
318
+ cont.loop = True
319
+ cont.autoplay = True
320
+ state["update"] = False
321
+
322
+ def on_exit(x, y): # pragma: no cover # pylint: disable=unused-argument
323
+ state["update"] = True
324
+
325
+ htmap_posxy = hv.streams.PointerXY(source=htmap)
326
+ htmap_posxy.add_subscriber(tap_plot_heatmap)
327
+ ls = hv.streams.MouseLeave(source=htmap)
328
+ ls.add_subscriber(on_exit)
329
+
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))
335
+
336
+ def to_line_tap_ds(
337
+ self,
338
+ dataset: xr.Dataset,
339
+ result_var: Parameter,
340
+ result_var_plots: List[Parameter] = None,
341
+ container: pn.pane.panel = pn.pane.panel,
342
+ **kwargs,
343
+ ) -> pn.Row:
344
+ htmap = self.to_line_ds(dataset, result_var).opts(tools=["hover"], **kwargs)
345
+ result_var_plots, cont_instances = self.setup_results_and_containers(
346
+ result_var_plots, container
347
+ )
348
+ title = pn.pane.Markdown("Selected: None")
349
+
350
+ state = dict(x=None, y=None, update=False)
351
+
352
+ def tap_plot_line(x, y): # pragma: no cover
353
+ # print(f"{x},{y}")
354
+ # print(dataset)
355
+
356
+ # xv = self.bench_cfg.input_vars[0].name
357
+ # yv = self.bench_cfg.input_vars[1].name
358
+
359
+ # x_nearest_new = get_nearest_coords1D(
360
+ # x, dataset.coords[self.bench_cfg.input_vars[0].name].data
361
+ # )
362
+ # y_nearest_new = get_nearest_coords1D(
363
+ # y, dataset.coords[self.bench_cfg.input_vars[1].name].data
364
+ # )
365
+
366
+ # kwargs = {xv: x, yv: y}
367
+
368
+ # nearest = get_nearest_coords(dataset, **kwargs)
369
+ # print(nearest)
370
+
371
+ x_nearest_new = get_nearest_coords1D(
372
+ x, dataset.coords[self.bench_cfg.input_vars[0].name].data
373
+ )
374
+
375
+ if x_nearest_new != state["x"]:
376
+ state["x"] = x_nearest_new
377
+ state["update"] = True
378
+
379
+ if self.plt_cnt_cfg.inputs_cnt > 1:
380
+ y_nearest_new = get_nearest_coords1D(
381
+ y, dataset.coords[self.bench_cfg.input_vars[1].name].data
382
+ )
383
+ if y_nearest_new != state["y"]:
384
+ state["y"] = y_nearest_new
385
+ state["update"] = True
386
+
387
+ if state["update"]:
388
+ kdims = {}
389
+ kdims[self.bench_cfg.input_vars[0].name] = state["x"]
390
+ if self.plt_cnt_cfg.inputs_cnt > 1:
391
+ kdims[self.bench_cfg.input_vars[1].name] = state["y"]
392
+
393
+ if hasattr(htmap, "current_key"):
394
+ for d, k in zip(htmap.kdims, htmap.current_key):
395
+ kdims[d.name] = k
396
+ for rv, cont in zip(result_var_plots, cont_instances):
397
+ ds = dataset[rv.name]
398
+ val = ds.sel(**kdims)
399
+ item = self.zero_dim_da_to_val(val)
400
+ title.object = "Selected: " + ", ".join([f"{k}:{v}" for k, v in kdims.items()])
401
+ cont.object = item
402
+ if hasattr(cont, "autoplay"): # container is a video, set to autoplay
403
+ cont.paused = False
404
+ cont.time = 0
405
+ cont.loop = True
406
+ cont.autoplay = True
407
+ state["update"] = False
408
+
409
+ def on_exit(x, y): # pragma: no cover # pylint: disable=unused-argument
410
+ state["update"] = True
411
+
412
+ htmap_posxy = hv.streams.PointerXY(source=htmap)
413
+ htmap_posxy.add_subscriber(tap_plot_line)
414
+ ls = hv.streams.MouseLeave(source=htmap)
415
+ ls.add_subscriber(on_exit)
416
+ bound_plot = pn.Column(title, *cont_instances)
417
+ return pn.Row(htmap, bound_plot)
418
+
419
+ def to_error_bar(self) -> hv.Bars:
420
+ return self.to_hv_dataset(ReduceType.REDUCE).to(hv.ErrorBars)
421
+
422
+ def to_points(self, reduce: ReduceType = ReduceType.AUTO) -> hv.Points:
423
+ ds = self.to_hv_dataset(reduce)
424
+ pt = ds.to(hv.Points)
425
+ if reduce:
426
+ pt *= ds.to(hv.ErrorBars)
427
+ return pt
428
+
429
+ def to_scatter(self, **kwargs) -> Optional[pn.panel]:
430
+ match_res = PlotFilter(
431
+ float_range=VarRange(0, 0), cat_range=VarRange(0, None), repeats_range=VarRange(1, 1)
432
+ ).matches_result(self.plt_cnt_cfg, "to_hvplot_scatter")
433
+ if match_res.overall:
434
+ hv_ds = self.to_hv_dataset(ReduceType.SQUEEZE)
435
+ by = None
436
+ subplots = False
437
+ if self.plt_cnt_cfg.cat_cnt > 1:
438
+ by = [v.name for v in self.bench_cfg.input_vars[1:]]
439
+ subplots = False
440
+ return hv_ds.data.hvplot.scatter(by=by, subplots=subplots, **kwargs).opts(
441
+ title=self.to_plot_title()
442
+ )
443
+ return match_res.to_panel(**kwargs)
444
+
445
+ # def to_scatter_jitter(self, **kwargs) -> Optional[hv.Scatter]:
446
+ # matches = PlotFilter(
447
+ # float_range=VarRange(0, 0),
448
+ # cat_range=VarRange(0, None),
449
+ # repeats_range=VarRange(2, None),
450
+ # input_range=VarRange(1, None),
451
+ # ).matches_result(self.plt_cnt_cfg, "to_scatter_jitter")
452
+ # if matches.overall:
453
+ # hv_ds = self.to_hv_dataset(ReduceType.NONE)
454
+
455
+ # by = None
456
+ # groupby = None
457
+ # subplots=False
458
+ # if self.plt_cnt_cfg.cat_cnt > 1:
459
+ # by = [v.name for v in self.bench_cfg.all_vars[1:]]
460
+ # subplots=False
461
+ # return hv_ds.data.hvplot.scatter(by=by,subplots=subplots, **kwargs).opts(title=self.to_plot_title())
462
+
463
+ # # pt = (
464
+ # # hv_ds.to(hv.Scatter)
465
+ # # .opts(jitter=0.1)
466
+ # # .overlay("repeat")
467
+ # # .opts(show_legend=False, title=self.to_plot_title(), **kwargs)
468
+ # # )
469
+ # # return pt
470
+ # return matches.to_panel()
471
+
472
+ # def to_scatter_jitter_multi(self, **kwargs) -> Optional[hv.Scatter]:
473
+ # matches = PlotFilter(
474
+ # float_range=VarRange(0, 0),
475
+ # cat_range=VarRange(0, None),
476
+ # repeats_range=VarRange(2, None),
477
+ # input_range=VarRange(1, None),
478
+ # ).matches_result(self.plt_cnt_cfg, "to_scatter_jitter")
479
+ # if matches.overall:
480
+ # hv_dataset = self.to_hv_dataset(ReduceType.NONE)
481
+
482
+ # print("KDIMS",hv_dataset.kdims)
483
+ # # hv_dataset.kdims =[hv_dataset.kdims[2],hv_dataset.kdims[1],hv_dataset.kdims[0]]
484
+ # # print("KDIMS",hv_dataset.kdims)
485
+
486
+ # # exit()
487
+ # cb = partial(self.to_scatter_jitter_da, **kwargs)
488
+ # return self.to_panes_multi_panel(hv_dataset, None, plot_callback=cb, target_dimension=3)
489
+ # return matches.to_panel()
490
+
491
+ # def to_scatter_jitter_da(self, ds: xr.Dataset, **kwargs) -> Optional[hv.Scatter]:
492
+ # matches = PlotFilter(
493
+ # float_range=VarRange(0, 0),
494
+ # cat_range=VarRange(0, None),
495
+ # repeats_range=VarRange(2, None),
496
+ # input_range=VarRange(1, None),
497
+ # ).matches_result(self.plt_cnt_cfg, "to_scatter_jitter")
498
+ # if matches.overall:
499
+
500
+ # print("DA IN",da)
501
+ # da = self.to_hv_dataset(ReduceType.NONE)
502
+ # hvds = hv.Dataset(da)
503
+ # # return None
504
+
505
+ # # print("DA FRESH",da)
506
+ # result_var = self.bench_cfg.result_vars[0]
507
+
508
+ # print(hvds.data.sizes)
509
+ # print("repeat" in hvds.data.sizes)
510
+ # # if "repeat" in hvds.data.sizes:
511
+ # # try:
512
+ # # pt = (
513
+ # # hvds.to(hv.Scatter)
514
+ # # .opts(jitter=0.1)
515
+ # # # .overlay()
516
+ # # .overlay("repeat")
517
+ # # .opts(show_legend=False, title=self.to_plot_title(), clabel=result_var.name, **kwargs)
518
+ # # )
519
+ # # except:
520
+ # pt = (
521
+ # hvds.to(hv.Scatter)
522
+ # .opts(jitter=0.1)
523
+ # # .overlay()
524
+ # # .overlay("repeat")
525
+ # .opts(show_legend=False, title=self.to_plot_title(), clabel=result_var.name, **kwargs)
526
+ # )
527
+ # return pt
528
+ # return matches.to_panel()
529
+
530
+ def to_scatter_jitter(
531
+ self,
532
+ result_var: Parameter = None,
533
+ **kwargs, # pylint: disable=unused-argument
534
+ ) -> List[hv.Scatter]:
535
+ return self.overlay_plots(partial(self.to_scatter_jitter_single, **kwargs))
536
+
537
+ def to_scatter_jitter_single(self, result_var: Parameter, **kwargs) -> Optional[hv.Scatter]:
538
+ matches = PlotFilter(
539
+ float_range=VarRange(0, 0),
540
+ cat_range=VarRange(0, None),
541
+ repeats_range=VarRange(2, None),
542
+ input_range=VarRange(1, None),
543
+ ).matches_result(self.plt_cnt_cfg, "to_scatter_jitter")
544
+ if matches.overall:
545
+ ds = self.to_hv_dataset(ReduceType.NONE)
546
+ pt = (
547
+ ds.to(hv.Scatter, vdims=[result_var.name], label=result_var.name)
548
+ .opts(jitter=0.1, show_legend=False, title=self.to_plot_title(), **kwargs)
549
+ .overlay("repeat")
550
+ )
551
+ return pt
552
+ return matches.to_panel()
553
+
554
+ def to_heatmap_single(
555
+ self, result_var: Parameter, reduce: ReduceType = ReduceType.AUTO, **kwargs
556
+ ) -> hv.HeatMap:
557
+ matches_res = PlotFilter(
558
+ float_range=VarRange(2, None),
559
+ cat_range=VarRange(0, None),
560
+ input_range=VarRange(1, None),
561
+ ).matches_result(self.plt_cnt_cfg, "to_heatmap")
562
+ if matches_res.overall:
563
+ z = result_var
564
+ title = f"{z.name} vs ("
565
+
566
+ for iv in self.bench_cfg.input_vars:
567
+ title += f" vs {iv.name}"
568
+ title += ")"
569
+
570
+ color_label = f"{z.name} [{z.units}]"
571
+
572
+ return self.to(hv.HeatMap, reduce).opts(clabel=color_label, **kwargs)
573
+ return matches_res.to_panel()
574
+
575
+ def to_heatmap_tap(
576
+ self,
577
+ result_var: Parameter,
578
+ reduce: ReduceType = ReduceType.AUTO,
579
+ width=800,
580
+ height=800,
581
+ **kwargs,
582
+ ):
583
+ htmap = self.to_heatmap_single(result_var, reduce).opts(
584
+ tools=["hover", "tap"], width=width, height=height
585
+ )
586
+ htmap_posxy = hv.streams.Tap(source=htmap, x=0, y=0)
587
+
588
+ def tap_plot(x, y):
589
+ kwargs[self.bench_cfg.input_vars[0].name] = x
590
+ kwargs[self.bench_cfg.input_vars[1].name] = y
591
+ return self.get_nearest_holomap(**kwargs).opts(width=width, height=height)
592
+
593
+ tap_htmap = hv.DynamicMap(tap_plot, streams=[htmap_posxy])
594
+ return htmap + tap_htmap
595
+
596
+ def to_nd_layout(self, hmap_name: str) -> hv.NdLayout:
597
+ return hv.NdLayout(self.get_hmap(hmap_name), kdims=self.bench_cfg.hmap_kdims).opts(
598
+ shared_axes=False, shared_datasource=False
599
+ )
600
+
601
+ def to_holomap(self, name: str = None) -> hv.HoloMap:
602
+ return hv.HoloMap(self.to_nd_layout(name)).opts(shared_axes=False)
603
+
604
+ def to_holomap_list(self, hmap_names: List[str] = None) -> hv.HoloMap:
605
+ if hmap_names is None:
606
+ hmap_names = [i.name for i in self.result_hmaps]
607
+ col = pn.Column()
608
+ for name in hmap_names:
609
+ self.to_holomap(name)
610
+ return col
611
+
612
+ def get_nearest_holomap(self, name: str = None, **kwargs):
613
+ canonical_inp = hmap_canonical_input(
614
+ get_nearest_coords(self.ds, collapse_list=True, **kwargs)
615
+ )
616
+ return self.get_hmap(name)[canonical_inp].opts(framewise=True)
617
+
618
+ def to_dynamic_map(self, name: str = None) -> hv.DynamicMap:
619
+ """use the values stored in the holomap dictionary to populate a dynamic map. Note that this is much faster than passing the holomap to a holomap object as the values are calculated on the fly"""
620
+
621
+ def cb(**kwargs):
622
+ return self.get_hmap(name)[hmap_canonical_input(kwargs)].opts(
623
+ framewise=True, shared_axes=False
624
+ )
625
+
626
+ kdims = []
627
+ for i in self.bench_cfg.input_vars + [self.bench_cfg.iv_repeat]:
628
+ kdims.append(i.as_dim(compute_values=True))
629
+
630
+ return hv.DynamicMap(cb, kdims=kdims)
631
+
632
+ def to_grid(self, inputs=None):
633
+ if inputs is None:
634
+ inputs = self.bench_cfg.inputs_as_str()
635
+ if len(inputs) > 2:
636
+ inputs = inputs[:2]
637
+ return self.to_holomap().grid(inputs)
638
+
639
+ def to_table(self):
640
+ return self.to(hv.Table, ReduceType.SQUEEZE)
641
+
642
+ def to_surface(self, result_var: Parameter = None, **kwargs) -> Optional[pn.panel]:
643
+ return self.filter(
644
+ self.to_surface_ds,
645
+ float_range=VarRange(2, None),
646
+ cat_range=VarRange(0, None),
647
+ input_range=VarRange(1, None),
648
+ reduce=ReduceType.REDUCE,
649
+ target_dimension=2,
650
+ result_var=result_var,
651
+ result_types=(ResultVar),
652
+ **kwargs,
653
+ )
654
+
655
+ def to_surface_ds(
656
+ self, dataset: xr.Dataset, result_var: Parameter, alpha: float = 0.3, **kwargs
657
+ ) -> Optional[pn.panel]:
658
+ """Given a benchCfg generate a 2D surface plot
659
+
660
+ Args:
661
+ result_var (Parameter): result variable to plot
662
+
663
+ Returns:
664
+ pn.pane.holoview: A 2d surface plot as a holoview in a pane
665
+ """
666
+ matches_res = PlotFilter(
667
+ float_range=VarRange(2, 2),
668
+ cat_range=VarRange(0, None),
669
+ vector_len=VarRange(1, 1),
670
+ result_vars=VarRange(1, 1),
671
+ ).matches_result(self.plt_cnt_cfg, "to_surface_hv")
672
+ if matches_res.overall:
673
+ # xr_cfg = plot_float_cnt_2(self.plt_cnt_cfg, result_var)
674
+
675
+ # TODO a warning suggests setting this parameter, but it does not seem to help as expected, leaving here to fix in the future
676
+ # hv.config.image_rtol = 1.0
677
+
678
+ mean = dataset[result_var.name]
679
+
680
+ hvds = hv.Dataset(dataset[result_var.name])
681
+
682
+ x = self.plt_cnt_cfg.float_vars[0]
683
+ y = self.plt_cnt_cfg.float_vars[1]
684
+
685
+ try:
686
+ surface = hvds.to(hv.Surface, vdims=[result_var.name])
687
+ surface = surface.opts(colorbar=True)
688
+ except Exception as e: # pylint: disable=broad-except
689
+ logging.warning(e)
690
+
691
+ if self.bench_cfg.repeats > 1:
692
+ std_dev = dataset[f"{result_var.name}_std"]
693
+
694
+ upper = mean + std_dev
695
+ upper.name = result_var.name
696
+
697
+ lower = mean - std_dev
698
+ lower.name = result_var.name
699
+
700
+ surface *= (
701
+ hv.Dataset(upper)
702
+ .to(hv.Surface)
703
+ .opts(alpha=alpha, colorbar=False, backend="plotly")
704
+ )
705
+ surface *= (
706
+ hv.Dataset(lower)
707
+ .to(hv.Surface)
708
+ .opts(alpha=alpha, colorbar=False, backend="plotly")
709
+ )
710
+
711
+ surface = surface.opts(
712
+ zlabel=f"{result_var.name} [{result_var.units}]",
713
+ title=f"{result_var.name} vs ({x.name} and {y.name})",
714
+ backend="plotly",
715
+ **kwargs,
716
+ )
717
+
718
+ if self.bench_cfg.render_plotly:
719
+ hv.extension("plotly")
720
+ out = surface
721
+ else:
722
+ # using render disabled the holoviews sliders :(
723
+ out = hv.render(surface, backend="plotly")
724
+ return pn.Column(out, name="surface_hv")
725
+
726
+ return matches_res.to_panel()
727
+
728
+ # def plot_scatter2D_hv(self, rv: ParametrizedSweep) -> pn.pane.Plotly:
729
+ # import plotly.express as px
730
+
731
+ # """Given a benchCfg generate a 2D scatter plot
732
+
733
+ # Args:
734
+ # bench_cfg (BenchCfg): description of benchmark
735
+ # rv (ParametrizedSweep): result variable to plot
736
+
737
+ # Returns:
738
+ # pn.pane.Plotly: A 3d volume plot as a holoview in a pane
739
+ # """
740
+
741
+ # # bench_cfg = wrap_long_time_labels(bench_cfg)
742
+ # self.ds.drop_vars("repeat")
743
+
744
+ # df = self.to_pandas()
745
+
746
+ # names = rv.index_names()
747
+
748
+ # return px.scatter(
749
+ # df, x=names[0], y=names[1], marginal_x="histogram", marginal_y="histogram"
750
+ # )
751
+
752
+
753
+ HoloviewResult.set_default_opts()