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