holobench 1.3.3__py3-none-any.whl → 1.3.5__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 CHANGED
@@ -5,6 +5,8 @@ from .bench_plot_server import BenchPlotServer
5
5
  from .variables.sweep_base import hash_sha1
6
6
  from .variables.inputs import IntSweep, FloatSweep, StringSweep, EnumSweep, BoolSweep, SweepBase
7
7
  from .variables.time import TimeSnapshot
8
+
9
+ from .variables.inputs import box
8
10
  from .variables.results import (
9
11
  ResultVar,
10
12
  ResultVec,
@@ -14,9 +16,11 @@ from .variables.results import (
14
16
  ResultString,
15
17
  ResultContainer,
16
18
  ResultReference,
19
+ ResultVolume,
17
20
  OptDir,
18
21
  curve,
19
22
  )
23
+
20
24
  from .plotting.plot_filter import VarRange, PlotFilter
21
25
  from .utils import (
22
26
  hmap_canonical_input,
@@ -25,6 +29,7 @@ from .utils import (
25
29
  gen_path,
26
30
  gen_image_path,
27
31
  gen_video_path,
32
+ lerp,
28
33
  )
29
34
  from .variables.parametrised_sweep import ParametrizedSweep
30
35
  from .caching import CachedParams
@@ -33,4 +38,4 @@ from .results.panel_result import PanelResult
33
38
  from .results.holoview_result import ReduceType, HoloviewResult
34
39
  from .bench_report import BenchReport
35
40
  from .job import Executors
36
- from .video_writer import VideoWriter
41
+ from .video_writer import VideoWriter, add_image
bencher/bench_cfg.py CHANGED
@@ -164,6 +164,15 @@ class BenchRunCfg(BenchPlotSrvCfg):
164
164
  doc="The function can be run serially or in parallel with different futures executors",
165
165
  )
166
166
 
167
+ plot_size = param.Integer(default=None, doc="Sets the width and height of the plot")
168
+ plot_width = param.Integer(
169
+ default=None,
170
+ doc="Sets with width of the plots, this will ovverride the plot_size parameter",
171
+ )
172
+ plot_height = param.Integer(
173
+ default=None, doc="Sets the height of the plot, this will ovverride the plot_size parameter"
174
+ )
175
+
167
176
  @staticmethod
168
177
  def from_cmd_line() -> BenchRunCfg: # pragma: no cover
169
178
  """create a BenchRunCfg by parsing command line arguments
@@ -424,12 +433,15 @@ class BenchCfg(BenchRunCfg):
424
433
  col.append(pn.pane.Markdown("## Results:"))
425
434
  return col
426
435
 
427
- def optuna_targets(self) -> List[str]:
428
- target_names = []
436
+ def optuna_targets(self, as_var=False) -> List[str]:
437
+ targets = []
429
438
  for rv in self.result_vars:
430
- if rv.direction != OptDir.none:
431
- target_names.append(rv.name)
432
- return target_names
439
+ if hasattr(rv, "direction") and rv.direction != OptDir.none:
440
+ if as_var:
441
+ targets.append(rv)
442
+ else:
443
+ targets.append(rv.name)
444
+ return targets
433
445
 
434
446
 
435
447
  class DimsCfg:
bencher/bencher.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  from datetime import datetime
3
- from itertools import product
3
+ from itertools import product, combinations
4
+
4
5
  from typing import Callable, List
5
6
  from copy import deepcopy
6
7
  import numpy as np
@@ -186,9 +187,72 @@ class Bench(BenchPlotServer):
186
187
  logging.info(f"setting worker {worker}")
187
188
  self.worker_input_cfg = worker_input_cfg
188
189
 
190
+ def sweep(
191
+ self,
192
+ input_vars: List[ParametrizedSweep] = None,
193
+ result_vars: List[ParametrizedSweep] = None,
194
+ const_vars: List[ParametrizedSweep] = None,
195
+ time_src: datetime = None,
196
+ description: str = None,
197
+ post_description: str = None,
198
+ pass_repeat: bool = False,
199
+ tag: str = "",
200
+ run_cfg: BenchRunCfg = None,
201
+ plot: bool = False,
202
+ ) -> BenchResult:
203
+ title = "Sweeping " + " vs ".join([self.get_name(i) for i in input_vars])
204
+ return self.plot_sweep(
205
+ title,
206
+ input_vars=input_vars,
207
+ result_vars=result_vars,
208
+ const_vars=const_vars,
209
+ time_src=time_src,
210
+ description=description,
211
+ post_description=post_description,
212
+ pass_repeat=pass_repeat,
213
+ tag=tag,
214
+ run_cfg=run_cfg,
215
+ plot=plot,
216
+ )
217
+
218
+ def sweep_sequential(
219
+ self,
220
+ title="",
221
+ input_vars: List[ParametrizedSweep] = None,
222
+ result_vars: List[ParametrizedSweep] = None,
223
+ const_vars: List[ParametrizedSweep] = None,
224
+ optimise_var: ParametrizedSweep = None,
225
+ run_cfg: BenchRunCfg = None,
226
+ group_size: int = 1,
227
+ iterations: int = 1,
228
+ relationship_cb=None,
229
+ ) -> List[BenchResult]:
230
+ results = []
231
+ if relationship_cb is None:
232
+ relationship_cb = combinations
233
+ for it in range(iterations):
234
+ for input_group in relationship_cb(input_vars, group_size):
235
+ title_gen = (
236
+ title + "Sweeping " + " vs ".join([self.get_name(i) for i in input_group])
237
+ )
238
+ if iterations > 1:
239
+ title_gen += f" iteration:{it}"
240
+ res = self.plot_sweep(
241
+ title=title_gen,
242
+ input_vars=list(input_group),
243
+ result_vars=result_vars,
244
+ const_vars=const_vars,
245
+ run_cfg=run_cfg,
246
+ plot=True,
247
+ )
248
+ if optimise_var is not None:
249
+ const_vars = res.get_optimal_inputs(optimise_var, True)
250
+ results.append(res)
251
+ return results
252
+
189
253
  def plot_sweep(
190
254
  self,
191
- title: str,
255
+ title: str = None,
192
256
  input_vars: List[ParametrizedSweep] = None,
193
257
  result_vars: List[ParametrizedSweep] = None,
194
258
  const_vars: List[ParametrizedSweep] = None,
@@ -248,6 +312,20 @@ class Bench(BenchPlotServer):
248
312
  else:
249
313
  const_vars = deepcopy(const_vars)
250
314
 
315
+ for i in range(len(input_vars)):
316
+ input_vars[i] = self.convert_vars_to_params(input_vars[i], "input")
317
+ for i in range(len(result_vars)):
318
+ result_vars[i] = self.convert_vars_to_params(result_vars[i], "result")
319
+
320
+ if isinstance(const_vars, dict):
321
+ const_vars = list(const_vars.items())
322
+
323
+ for i in range(len(const_vars)):
324
+ # consts come as tuple pairs
325
+ cv_list = list(const_vars[i])
326
+ cv_list[0] = self.convert_vars_to_params(cv_list[0], "const")
327
+ const_vars[i] = cv_list
328
+
251
329
  if run_cfg is None:
252
330
  if self.run_cfg is None:
253
331
  run_cfg = BenchRunCfg()
@@ -261,11 +339,24 @@ class Bench(BenchPlotServer):
261
339
 
262
340
  self.last_run_cfg = run_cfg
263
341
 
342
+ if title is None:
343
+ if len(input_vars) > 0:
344
+ title = "Sweeping " + " vs ".join([i.name for i in input_vars])
345
+ elif len(const_vars) > 0:
346
+ title = "Constant Value"
347
+ if len(const_vars) > 1:
348
+ title += "s"
349
+ title += ": " + ", ".join([f"{c[0].name}={c[1]}" for c in const_vars])
350
+ else:
351
+ raise RuntimeError("you must pass a title, or define inputs or consts")
352
+
264
353
  if run_cfg.level > 0:
265
354
  inputs = []
266
- for i in input_vars:
267
- inputs.append(i.with_level(run_cfg.level))
268
- input_vars = inputs
355
+ print(input_vars)
356
+ if len(input_vars) > 0:
357
+ for i in input_vars:
358
+ inputs.append(i.with_level(run_cfg.level))
359
+ input_vars = inputs
269
360
 
270
361
  # if any of the inputs have been include as constants, remove those variables from the list of constants
271
362
  with suppress(ValueError, AttributeError):
@@ -276,14 +367,6 @@ class Bench(BenchPlotServer):
276
367
  const_vars.remove(c)
277
368
  logging.info(f"removing {i.name} from constants")
278
369
 
279
- for i in input_vars:
280
- self.check_var_is_a_param(i, "input")
281
- for i in result_vars:
282
- self.check_var_is_a_param(i, "result")
283
- for i in const_vars:
284
- # consts come as tuple pairs
285
- self.check_var_is_a_param(i[0], "const")
286
-
287
370
  result_hmaps = []
288
371
  result_vars_only = []
289
372
  for i in result_vars:
@@ -368,7 +451,12 @@ class Bench(BenchPlotServer):
368
451
  self.results.append(bench_res)
369
452
  return bench_res
370
453
 
371
- def check_var_is_a_param(self, variable: param.Parameter, var_type: str):
454
+ def get_name(self, var):
455
+ if isinstance(var, param.Parameter):
456
+ return var.name
457
+ return var
458
+
459
+ def convert_vars_to_params(self, variable: param.Parameter, var_type: str):
372
460
  """check that a variable is a subclass of param
373
461
 
374
462
  Args:
@@ -378,10 +466,13 @@ class Bench(BenchPlotServer):
378
466
  Raises:
379
467
  TypeError: the input variable type is not a param.
380
468
  """
469
+ if isinstance(variable, str):
470
+ variable = self.worker_class_instance.param.objects(instance=False)[variable]
381
471
  if not isinstance(variable, param.Parameter):
382
472
  raise TypeError(
383
473
  f"You need to use {var_type}_vars =[{self.worker_input_cfg}.param.your_variable], instead of {var_type}_vars =[{self.worker_input_cfg}.your_variable]"
384
474
  )
475
+ return variable
385
476
 
386
477
  def cache_results(self, bench_res: BenchResult, bench_cfg_hash: int) -> None:
387
478
  with Cache("cachedir/benchmark_inputs", size_limit=self.cache_size) as c:
@@ -1,7 +1,7 @@
1
1
  import bencher as bch
2
2
  import numpy as np
3
3
  import matplotlib.pyplot as plt
4
- from matplotlib.animation import ArtistAnimation
4
+ import panel as pn
5
5
 
6
6
 
7
7
  # code from https://ipython-books.github.io/124-simulating-a-partial-differential-equation-reaction-diffusion-systems-and-turing-patterns/
@@ -11,11 +11,12 @@ class TuringPattern(bch.ParametrizedSweep):
11
11
  tau = bch.FloatSweep(default=0.1, bounds=(0.01, 0.5))
12
12
  k = bch.FloatSweep(default=-0.005, bounds=(-0.01, 0.01))
13
13
 
14
- size = bch.IntSweep(default=50, bounds=(30, 200), doc="size of the 2D grid")
14
+ size = bch.IntSweep(default=30, bounds=(30, 200), doc="size of the 2D grid")
15
15
  time = bch.FloatSweep(default=20.0, bounds=(1, 100), doc="total time of simulation")
16
16
  dt = bch.FloatSweep(default=0.001, doc="simulation time step")
17
17
 
18
18
  video = bch.ResultVideo()
19
+ score = bch.ResultVar()
19
20
 
20
21
  def laplacian(self, Z, dx):
21
22
  Ztop = Z[0:-2, 1:-1]
@@ -57,20 +58,18 @@ class TuringPattern(bch.ParametrizedSweep):
57
58
  fig, ax = plt.subplots(frameon=False, figsize=(2, 2))
58
59
  fig.set_tight_layout(True)
59
60
  ax.set_axis_off()
60
-
61
- artists = []
62
-
61
+ vid_writer = bch.VideoWriter()
63
62
  for i in range(n):
64
63
  self.update(U, V, dx)
65
64
  if i % 500 == 0:
66
- artists.append([ax.imshow(U)])
67
-
68
- ani = ArtistAnimation(fig=fig, artists=artists, interval=60, blit=True)
69
- path = bch.gen_video_path("turing", ".mp4")
70
- # path = self.gen_path("turing", "vid", ".gif")
71
- print(f"saving {len(artists)} frames")
72
- ani.save(path)
73
- self.video = path
65
+ ax.imshow(U)
66
+ fig.canvas.draw()
67
+ rgb = np.array(fig.canvas.renderer.buffer_rgba())
68
+ vid_writer.append(rgb)
69
+
70
+ self.video = vid_writer.write()
71
+
72
+ self.score = self.alpha + self.beta
74
73
  return super().__call__()
75
74
 
76
75
 
@@ -91,8 +90,35 @@ def example_video(
91
90
  return bench
92
91
 
93
92
 
93
+ def example_video_tap(
94
+ run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
95
+ ) -> bch.Bench: # pragma: no cover
96
+ tp = TuringPattern()
97
+
98
+ run_cfg.use_sample_cache = False
99
+ # run_cfg.use_optuna = True
100
+ run_cfg.auto_plot = False
101
+ run_cfg.run_tag = "3"
102
+ bench = tp.to_bench(run_cfg=run_cfg, report=report)
103
+
104
+ res = bench.plot_sweep(
105
+ "phase",
106
+ input_vars=["alpha", "beta"],
107
+ # result_vars=["video","score"],
108
+ run_cfg=run_cfg,
109
+ )
110
+
111
+ bench.report.append(res.describe_sweep())
112
+ bench.report.append(
113
+ res.to_heatmap(tp.param.score, tap_var=tp.param.video, tap_container=pn.pane.Video)
114
+ )
115
+
116
+ return bench
117
+
118
+
94
119
  if __name__ == "__main__":
95
120
  run_cfg_ex = bch.BenchRunCfg()
96
121
  run_cfg_ex.level = 2
97
122
 
98
- example_video(run_cfg_ex).report.show()
123
+ # example_video(run_cfg_ex).report.show()
124
+ example_video_tap(run_cfg_ex).report.show()
@@ -100,20 +100,21 @@ class BenchMeta(bch.ParametrizedSweep):
100
100
  run_cfg.level = self.level
101
101
  run_cfg.repeats = self.sample_with_repeats
102
102
  run_cfg.over_time = self.sample_over_time
103
+ run_cfg.plot_size = 500
103
104
 
104
105
  bench = bch.Bench("benchable", BenchableObject(), run_cfg=run_cfg)
105
106
 
106
107
  inputs_vars_float = [
107
- BenchableObject.param.float1,
108
- BenchableObject.param.float2,
109
- BenchableObject.param.float3,
110
- BenchableObject.param.sigma,
108
+ "float1",
109
+ "float2",
110
+ "float3",
111
+ "sigma",
111
112
  ]
112
113
 
113
114
  inputs_vars_cat = [
114
- BenchableObject.param.noisy,
115
- BenchableObject.param.noise_distribution,
116
- BenchableObject.param.negate_output,
115
+ "noisy",
116
+ "noise_distribution",
117
+ "negate_output",
117
118
  ]
118
119
 
119
120
  input_vars = (
@@ -131,7 +132,7 @@ class BenchMeta(bch.ParametrizedSweep):
131
132
  )
132
133
 
133
134
  self.plots = bch.ResultReference()
134
- self.plots.obj = res.to_auto(width=500, height=300)
135
+ self.plots.obj = res.to_auto()
135
136
 
136
137
  # self.plots.obj = res.to_heatmap_multi()
137
138
 
@@ -25,7 +25,7 @@ class ToyOptimisationProblem(bch.ParametrizedSweep):
25
25
  bump_scale = bch.FloatSweep(default=1.5, bounds=[1, 10])
26
26
 
27
27
  # RESULTS
28
- output = bch.ResultVar(bch.OptDir.minimize)
28
+ output = bch.ResultVar("ul", bch.OptDir.minimize)
29
29
 
30
30
  def rastrigin(self, **kwargs) -> dict:
31
31
  """A modified version of the rastrigin function which is very difficult to find the global optimum
@@ -58,7 +58,7 @@ def optuna_rastrigin(
58
58
  # n_trials=30
59
59
  # )
60
60
 
61
- run_cfg.use_optuna = True
61
+ # run_cfg.use_optuna = True
62
62
  res = bench.plot_sweep(
63
63
  "Rastrigin",
64
64
  input_vars=[explorer.param.input1, explorer.param.input2],
@@ -67,7 +67,7 @@ def optuna_rastrigin(
67
67
  )
68
68
 
69
69
  bench.report.append(res.to_optuna_plots())
70
- bench.report.append(res.to_optuna_from_sweep(bench.worker))
70
+ bench.report.append(res.to_optuna_from_sweep(bench))
71
71
  bench.report.append_markdown(
72
72
  f"The optimal value should be input1:{-optimal_value},input2:{-optimal_value} with a value of 0"
73
73
  )
@@ -14,7 +14,6 @@ from bencher.bench_cfg import BenchCfg
14
14
 
15
15
  from bencher.variables.inputs import IntSweep, FloatSweep, StringSweep, EnumSweep, BoolSweep
16
16
  from bencher.variables.time import TimeSnapshot, TimeEvent
17
- from bencher.variables.results import OptDir
18
17
 
19
18
  from bencher.variables.parametrised_sweep import ParametrizedSweep
20
19
 
@@ -33,9 +32,8 @@ def optuna_grid_search(bench_cfg: BenchCfg) -> optuna.Study:
33
32
  for iv in bench_cfg.all_vars:
34
33
  search_space[iv.name] = iv.values(bench_cfg.debug)
35
34
  directions = []
36
- for rv in bench_cfg.result_vars:
37
- if rv.direction != OptDir.none:
38
- directions.append(rv.direction)
35
+ for rv in bench_cfg.optuna_targets(True):
36
+ directions.append(rv.direction)
39
37
 
40
38
  study = optuna.create_study(
41
39
  sampler=optuna.samplers.GridSampler(search_space),
@@ -76,9 +74,8 @@ def summarise_trial(trial: optuna.trial, bench_cfg: BenchCfg) -> List[str]:
76
74
  for k, v in trial.params.items():
77
75
  output.append(f"{sep}{sep}{k}:{v}")
78
76
  output.append(f"{sep}Results:")
79
- for it, rv in enumerate(bench_cfg.result_vars):
80
- if rv.direction != OptDir.none:
81
- output.append(f"{sep}{sep}{rv.name}:{trial.values[it]}")
77
+ for it, rv in enumerate(bench_cfg.optuna_targets()):
78
+ output.append(f"{sep}{sep}{rv}:{trial.values[it]}")
82
79
  return output
83
80
 
84
81
 
@@ -7,10 +7,6 @@ from bencher.results.plotly_result import PlotlyResult
7
7
  from bencher.results.holoview_result import HoloviewResult
8
8
  from bencher.results.bench_result_base import EmptyContainer
9
9
 
10
- # from bencher.results.heatmap_result import HeatMapResult
11
-
12
- # from bencher.results.seaborn_result import SeabornResult
13
-
14
10
 
15
11
  class BenchResult(PlotlyResult, HoloviewResult):
16
12
 
@@ -40,12 +36,18 @@ class BenchResult(PlotlyResult, HoloviewResult):
40
36
  def to_auto(
41
37
  self,
42
38
  plot_list: List[callable] = None,
39
+ remove_plots: List[callable] = None,
43
40
  **kwargs,
44
41
  ) -> List[pn.panel]:
45
42
  self.plt_cnt_cfg.print_debug = False
46
43
 
47
44
  if plot_list is None:
48
45
  plot_list = BenchResult.default_plot_callbacks()
46
+ if remove_plots is not None:
47
+ for p in remove_plots:
48
+ plot_list.remove(p)
49
+
50
+ kwargs = self.set_plot_size(**kwargs)
49
51
 
50
52
  row = EmptyContainer(pn.Row())
51
53
  for plot_callback in plot_list:
@@ -61,9 +63,6 @@ class BenchResult(PlotlyResult, HoloviewResult):
61
63
  )
62
64
  return row.pane
63
65
 
64
- def to_auto_da(self):
65
- pass
66
-
67
66
  def to_auto_plots(self, **kwargs) -> List[pn.panel]:
68
67
  """Given the dataset result of a benchmark run, automatically dedeuce how to plot the data based on the types of variables that were sampled
69
68
 
@@ -73,6 +72,7 @@ class BenchResult(PlotlyResult, HoloviewResult):
73
72
  Returns:
74
73
  pn.pane: A panel containing plot results
75
74
  """
75
+
76
76
  plot_cols = pn.Column()
77
77
  plot_cols.append(self.to_sweep_summary(name="Plots View"))
78
78
  plot_cols.append(self.to_auto(**kwargs))
@@ -5,7 +5,7 @@ import xarray as xr
5
5
  from param import Parameter
6
6
  import holoviews as hv
7
7
  from functools import partial
8
- from bencher.utils import int_to_col, color_tuple_to_css
8
+ from bencher.utils import int_to_col, color_tuple_to_css, callable_name
9
9
 
10
10
  from bencher.variables.parametrised_sweep import ParametrizedSweep
11
11
  from bencher.variables.results import OptDir
@@ -141,16 +141,20 @@ class BenchResultBase(OptunaResult):
141
141
  return indicies
142
142
 
143
143
  def get_optimal_inputs(
144
- self, result_var: ParametrizedSweep, keep_existing_consts: bool = True
145
- ) -> Tuple[ParametrizedSweep, Any]:
144
+ self,
145
+ result_var: ParametrizedSweep,
146
+ keep_existing_consts: bool = True,
147
+ as_dict: bool = False,
148
+ ) -> Tuple[ParametrizedSweep, Any] | dict[ParametrizedSweep, Any]:
146
149
  """Get a list of tuples of optimal variable names and value pairs, that can be fed in as constant values to subsequent parameter sweeps
147
150
 
148
151
  Args:
149
152
  result_var (bch.ParametrizedSweep): Optimal values of this result variable
150
153
  keep_existing_consts (bool): Include any const values that were defined as part of the parameter sweep
154
+ as_dict (bool): return value as a dictionary
151
155
 
152
156
  Returns:
153
- Tuple[bch.ParametrizedSweep, Any]: Tuples of variable name and optimal values
157
+ Tuple[bch.ParametrizedSweep, Any]|[ParametrizedSweep, Any]: Tuples of variable name and optimal values
154
158
  """
155
159
  da = self.get_optimal_value_indices(result_var)
156
160
  if keep_existing_consts:
@@ -169,6 +173,8 @@ class BenchResultBase(OptunaResult):
169
173
  output.append((iv, max(da.coords[iv.name].values[()])))
170
174
 
171
175
  logging.info(f"Maximum value of {iv.name}: {output[-1][1]}")
176
+ if as_dict:
177
+ return dict(output)
172
178
  return output
173
179
 
174
180
  def describe_sweep(self):
@@ -235,6 +241,8 @@ class BenchResultBase(OptunaResult):
235
241
  if hv_dataset is None:
236
242
  hv_dataset = self.to_hv_dataset()
237
243
  row = EmptyContainer(pn.Row())
244
+
245
+ # kwargs= self.set_plot_size(**kwargs)
238
246
  for rv in self.get_results_var_list(result_var):
239
247
  if result_types is None or isinstance(rv, result_types):
240
248
  row.append(
@@ -273,7 +281,7 @@ class BenchResultBase(OptunaResult):
273
281
  repeats_range=repeats_range,
274
282
  input_range=input_range,
275
283
  )
276
- matches_res = plot_filter.matches_result(self.plt_cnt_cfg, plot_callback.__name__)
284
+ matches_res = plot_filter.matches_result(self.plt_cnt_cfg, callable_name(plot_callback))
277
285
  if matches_res.overall:
278
286
  return self.map_plot_panes(
279
287
  plot_callback=plot_callback,
@@ -294,6 +302,8 @@ class BenchResultBase(OptunaResult):
294
302
  **kwargs,
295
303
  ):
296
304
  dims = len(hv_dataset.dimensions())
305
+ if target_dimension is None:
306
+ target_dimension = dims
297
307
  return self._to_panes_da(
298
308
  hv_dataset.data,
299
309
  plot_callback=plot_callback,
@@ -8,7 +8,7 @@ from functools import partial
8
8
  import hvplot.xarray # noqa pylint: disable=duplicate-code,unused-import
9
9
  import xarray as xr
10
10
 
11
- from bencher.utils import hmap_canonical_input, get_nearest_coords
11
+ from bencher.utils import hmap_canonical_input, get_nearest_coords, get_nearest_coords1D
12
12
  from bencher.results.panel_result import PanelResult
13
13
  from bencher.results.bench_result_base import ReduceType
14
14
 
@@ -173,13 +173,27 @@ class HoloviewResult(PanelResult):
173
173
  return pt.opts(legend_position="right").overlay()
174
174
  return pt.opts(legend_position="right")
175
175
 
176
- def to_heatmap(self, result_var: Parameter = None, **kwargs) -> Optional[pn.panel]:
176
+ def to_heatmap(
177
+ self,
178
+ result_var: Parameter = None,
179
+ tap_var=None,
180
+ tap_container=None,
181
+ target_dimension=2,
182
+ **kwargs,
183
+ ) -> Optional[pn.panel]:
184
+ if tap_var is None:
185
+ heatmap_cb = self.to_heatmap_ds
186
+ else:
187
+ heatmap_cb = partial(
188
+ self.to_heatmap_container_tap_ds, result_var_plot=tap_var, container=tap_container
189
+ )
190
+
177
191
  return self.filter(
178
- self.to_heatmap_ds,
192
+ heatmap_cb,
179
193
  float_range=VarRange(2, None),
180
194
  cat_range=VarRange(0, None),
181
195
  input_range=VarRange(1, None),
182
- target_dimension=2,
196
+ target_dimension=target_dimension,
183
197
  result_var=result_var,
184
198
  result_types=(ResultVar),
185
199
  **kwargs,
@@ -189,9 +203,6 @@ class HoloviewResult(PanelResult):
189
203
  self, dataset: xr.Dataset, result_var: Parameter, **kwargs
190
204
  ) -> Optional[hv.HeatMap]:
191
205
  if len(dataset.dims) >= 2:
192
- # dims = [d for d in da.sizes]
193
- # x = dims[0]
194
- # y = dims[1]
195
206
  x = self.plt_cnt_cfg.float_vars[0].name
196
207
  y = self.plt_cnt_cfg.float_vars[1].name
197
208
  C = result_var.name
@@ -200,6 +211,50 @@ class HoloviewResult(PanelResult):
200
211
  return dataset.hvplot.heatmap(x=x, y=y, C=C, cmap="plasma", **time_args, **kwargs)
201
212
  return None
202
213
 
214
+ def to_heatmap_container_tap_ds(
215
+ self,
216
+ dataset: xr.Dataset,
217
+ result_var: Parameter,
218
+ result_var_plot: Parameter,
219
+ container: pn.pane.panel = pn.pane.panel,
220
+ **kwargs,
221
+ ) -> pn.Row:
222
+ htmap = self.to_heatmap_ds(dataset, result_var).opts(tools=["hover", "tap"], **kwargs)
223
+ htmap_posxy = hv.streams.Tap(source=htmap, x=0, y=0)
224
+
225
+ container_instance = container(**kwargs)
226
+ title = pn.pane.Markdown("Selected: None")
227
+
228
+ def tap_plot(x, y): # pragma: no cover
229
+ x_nearest = get_nearest_coords1D(
230
+ x, dataset.coords[self.bench_cfg.input_vars[0].name].data
231
+ )
232
+ y_nearest = get_nearest_coords1D(
233
+ y, dataset.coords[self.bench_cfg.input_vars[1].name].data
234
+ )
235
+ kdims = {}
236
+ kdims[self.bench_cfg.input_vars[0].name] = x_nearest
237
+ kdims[self.bench_cfg.input_vars[1].name] = y_nearest
238
+
239
+ if hasattr(htmap, "current_key"):
240
+ for d, k in zip(htmap.kdims, htmap.current_key):
241
+ kdims[d.name] = k
242
+
243
+ ds = dataset[result_var_plot.name]
244
+ val = ds.sel(**kdims)
245
+ item = self.zero_dim_da_to_val(val)
246
+ title.object = "Selected: " + ", ".join([f"{k}:{v}" for k, v in kdims.items()])
247
+ container_instance.object = item
248
+ if hasattr(container, "autoplay"): # container is a video, set to autoplay
249
+ container_instance.paused = False
250
+ container_instance.time = 0
251
+ container_instance.loop = True
252
+ container_instance.autoplay = True
253
+
254
+ htmap_posxy.add_subscriber(tap_plot)
255
+ bound_plot = pn.Column(title, container_instance)
256
+ return pn.Row(htmap, bound_plot)
257
+
203
258
  def to_error_bar(self) -> hv.Bars:
204
259
  return self.to_hv_dataset(ReduceType.REDUCE).to(hv.ErrorBars)
205
260
 
@@ -312,7 +367,9 @@ class HoloviewResult(PanelResult):
312
367
  # return matches.to_panel()
313
368
 
314
369
  def to_scatter_jitter(
315
- self, result_var: Parameter = None, **kwargs # pylint: disable=unused-argument
370
+ self,
371
+ result_var: Parameter = None,
372
+ **kwargs, # pylint: disable=unused-argument
316
373
  ) -> List[hv.Scatter]:
317
374
  return self.overlay_plots(partial(self.to_scatter_jitter_single, **kwargs))
318
375
 
@@ -1,4 +1,7 @@
1
+ from __future__ import annotations
1
2
  from typing import List
3
+ from copy import deepcopy
4
+
2
5
  import numpy as np
3
6
  import optuna
4
7
  import panel as pn
@@ -15,7 +18,6 @@ from optuna.visualization import (
15
18
  )
16
19
  from bencher.utils import hmap_canonical_input
17
20
  from bencher.variables.time import TimeSnapshot, TimeEvent
18
- from bencher.variables.results import OptDir
19
21
  from bencher.bench_cfg import BenchCfg
20
22
  from bencher.plotting.plt_cnt_cfg import PltCntCfg
21
23
 
@@ -122,25 +124,34 @@ class OptunaResult:
122
124
 
123
125
  return self.collect_optuna_plots()
124
126
 
125
- def to_optuna_from_sweep(self, worker, n_trials=30):
126
- optu = self.to_optuna_from_results(worker, n_trials=n_trials)
127
+ def to_optuna_from_sweep(self, bench, n_trials=30):
128
+ optu = self.to_optuna_from_results(
129
+ bench.worker, n_trials=n_trials, extra_results=bench.results
130
+ )
127
131
  return summarise_optuna_study(optu)
128
132
 
129
- def to_optuna_from_results(self, worker, n_trials=100, sampler=optuna.samplers.TPESampler()):
133
+ def to_optuna_from_results(
134
+ self,
135
+ worker,
136
+ n_trials=100,
137
+ extra_results: List[OptunaResult] = None,
138
+ sampler=optuna.samplers.TPESampler(),
139
+ ):
130
140
  directions = []
131
- for rv in self.bench_cfg.result_vars:
132
- if rv.direction != OptDir.none:
133
- directions.append(rv.direction)
141
+ for rv in self.bench_cfg.optuna_targets(True):
142
+ directions.append(rv.direction)
134
143
 
135
144
  study = optuna.create_study(
136
145
  sampler=sampler, directions=directions, study_name=self.bench_cfg.title
137
146
  )
138
147
 
139
148
  # add already calculated results
140
- if len(self.ds.sizes) > 0:
141
- study.add_trials(self.bench_results_to_optuna_trials(True))
149
+ results_list = extra_results if extra_results is not None else [self]
150
+ for res in results_list:
151
+ if len(res.ds.sizes) > 0:
152
+ study.add_trials(res.bench_results_to_optuna_trials(True))
142
153
 
143
- def wrapped(trial):
154
+ def wrapped(trial) -> tuple:
144
155
  kwargs = {}
145
156
  for iv in self.bench_cfg.input_vars:
146
157
  kwargs[iv.name] = sweep_var_to_suggest(iv, trial)
@@ -197,9 +208,8 @@ class OptunaResult:
197
208
  else:
198
209
  params[i.name] = row[1][i.name]
199
210
 
200
- for r in self.bench_cfg.result_vars:
201
- if r.direction != OptDir.none:
202
- values.append(row[1][r.name])
211
+ for r in self.bench_cfg.optuna_targets():
212
+ values.append(row[1][r])
203
213
 
204
214
  trials.append(
205
215
  optuna.trial.create_trial(
@@ -322,3 +332,23 @@ class OptunaResult:
322
332
  # for it, rv in enumerate(bench_cfg.result_vars):
323
333
  # bench_cfg.ds[rv.name].loc[t.params] = t.values[it]
324
334
  # return bench_cfg
335
+
336
+ def deep(self) -> OptunaResult: # pragma: no cover
337
+ """Return a deep copy of these results"""
338
+ return deepcopy(self)
339
+
340
+ def set_plot_size(self, **kwargs) -> dict:
341
+ if "width" not in kwargs:
342
+ if self.bench_cfg.plot_size is not None:
343
+ kwargs["width"] = self.bench_cfg.plot_size
344
+ # specific width overrrides general size
345
+ if self.bench_cfg.plot_width is not None:
346
+ kwargs["width"] = self.bench_cfg.plot_width
347
+
348
+ if "height" not in kwargs:
349
+ if self.bench_cfg.plot_size is not None:
350
+ kwargs["height"] = self.bench_cfg.plot_size
351
+ # specific height overrrides general size
352
+ if self.bench_cfg.plot_height is not None:
353
+ kwargs["height"] = self.bench_cfg.plot_height
354
+ return kwargs
@@ -71,14 +71,18 @@ class PanelResult(BenchResultBase):
71
71
 
72
72
  def zero_dim_da_to_val(self, da_ds: xr.DataArray | xr.Dataset) -> Any:
73
73
  # todo this is really horrible, need to improve
74
+ dim = None
74
75
  if isinstance(da_ds, xr.Dataset):
75
76
  dim = list(da_ds.keys())[0]
76
77
  da = da_ds[dim]
77
78
  else:
78
79
  da = da_ds
80
+
79
81
  for k in da.coords.keys():
80
82
  dim = k
81
83
  break
84
+ if dim is None:
85
+ return da_ds.values.squeeze().item()
82
86
  return da.expand_dims(dim).values[0]
83
87
 
84
88
  def ds_to_container(
@@ -86,16 +90,21 @@ class PanelResult(BenchResultBase):
86
90
  ) -> Any:
87
91
  val = self.zero_dim_da_to_val(dataset[result_var.name])
88
92
  if isinstance(result_var, ResultReference):
89
- val = self.object_index[val].obj
93
+ ref = self.object_index[val]
94
+ val = ref.obj
95
+ if ref.container is not None:
96
+ return ref.container(val, **kwargs)
90
97
  if container is not None:
91
98
  return container(val, styles={"background": "white"}, **kwargs)
92
99
  return val
93
100
 
94
101
  def to_panes(
95
- self, result_var: Parameter = None, target_dimension: int = 0, **kwargs
102
+ self, result_var: Parameter = None, target_dimension: int = 0, container=None, **kwargs
96
103
  ) -> Optional[pn.pane.panel]:
104
+ if container is None:
105
+ container = pn.pane.panel
97
106
  return self.map_plot_panes(
98
- partial(self.ds_to_container, container=pn.pane.panel),
107
+ partial(self.ds_to_container, container=container),
99
108
  hv_dataset=self.to_hv_dataset(ReduceType.SQUEEZE),
100
109
  target_dimension=target_dimension,
101
110
  result_var=result_var,
bencher/utils.py CHANGED
@@ -7,6 +7,8 @@ import math
7
7
  from colorsys import hsv_to_rgb
8
8
  from pathlib import Path
9
9
  from uuid import uuid4
10
+ from functools import partial
11
+ from typing import Callable, Any
10
12
 
11
13
 
12
14
  def hmap_canonical_input(dic: dict) -> tuple:
@@ -55,6 +57,12 @@ def get_nearest_coords(dataset: xr.Dataset, collapse_list=False, **kwargs) -> di
55
57
  return cd2
56
58
 
57
59
 
60
+ def get_nearest_coords1D(val: Any, coords) -> Any:
61
+ if isinstance(val, (int, float)):
62
+ return min(coords, key=lambda x_: abs(x_ - val))
63
+ return val
64
+
65
+
58
66
  def hash_sha1(var: any) -> str:
59
67
  """A hash function that avoids the PYTHONHASHSEED 'feature' which returns a different hash value each time the program is run"""
60
68
  return hashlib.sha1(str(var).encode("ASCII")).hexdigest()
@@ -106,6 +114,13 @@ def int_to_col(int_val, sat=0.5, val=0.95, alpha=-1) -> tuple[float, float, floa
106
114
  return rgb
107
115
 
108
116
 
117
+ def lerp(value, input_low: float, input_high: float, output_low: float, output_high: float):
118
+ input_low = float(input_low)
119
+ return output_low + ((float(value) - input_low) / (float(input_high) - input_low)) * (
120
+ float(output_high) - output_low
121
+ )
122
+
123
+
109
124
  def color_tuple_to_css(color: tuple[float, float, float]) -> str:
110
125
  return f"rgb{(color[0] * 255, color[1] * 255, color[2] * 255)}"
111
126
 
@@ -122,3 +137,12 @@ def gen_video_path(video_name: str, extension: str = ".webm") -> str:
122
137
 
123
138
  def gen_image_path(image_name: str, filetype=".png") -> str:
124
139
  return gen_path(image_name, "img", filetype)
140
+
141
+
142
+ def callable_name(any_callable: Callable[..., Any]) -> str:
143
+ if isinstance(any_callable, partial):
144
+ return any_callable.func.__name__
145
+ try:
146
+ return any_callable.__name__
147
+ except AttributeError:
148
+ return str(any_callable)
@@ -72,7 +72,7 @@ class EnumSweep(SweepSelector):
72
72
  __slots__ = shared_slots
73
73
 
74
74
  def __init__(
75
- self, enum_type: Enum | List[Enum], units="", samples=None, samples_debug=2, **params
75
+ self, enum_type: Enum | List[Enum], units=" ", samples=None, samples_debug=2, **params
76
76
  ):
77
77
  # The enum can either be an Enum type or a list of enums
78
78
  list_of_enums = isinstance(enum_type, list)
@@ -132,7 +132,7 @@ class ParametrizedSweep(Parameterized):
132
132
  assert isinstance(override_defaults, list)
133
133
  for p in override_defaults:
134
134
  inp = filter(partial(ParametrizedSweep.filter_fn, p_name=p[0].name), inp)
135
- return override_defaults + [(i, i.default) for i in inp]
135
+ return override_defaults + [[i, i.default] for i in inp]
136
136
 
137
137
  @classmethod
138
138
  def get_results_only(cls) -> List[Parameter]:
@@ -1,6 +1,7 @@
1
1
  from enum import auto
2
- from typing import List
2
+ from typing import List, Callable, Any
3
3
 
4
+ import panel as pn
4
5
  import param
5
6
  from param import Number
6
7
  from strenum import StrEnum
@@ -23,6 +24,7 @@ class ResultVar(Number):
23
24
 
24
25
  def __init__(self, units="ul", direction: OptDir = OptDir.minimize, **params):
25
26
  Number.__init__(self, **params)
27
+ assert isinstance(units, str)
26
28
  self.units = units
27
29
  self.default = 0 # json is terrible and does not support nan values
28
30
  self.direction = direction
@@ -136,6 +138,29 @@ class ResultContainer(param.Parameter):
136
138
 
137
139
 
138
140
  class ResultReference(param.Parameter):
141
+ """Use this class to save arbitrary objects that are not picklable or native to panel. You can pass a container callback that takes the object and returns a panel pane to be displayed"""
142
+
143
+ __slots__ = ["units", "obj", "container"]
144
+
145
+ def __init__(
146
+ self,
147
+ obj: Any = None,
148
+ container: Callable[Any, pn.pane.panel] = None,
149
+ default: Any = None,
150
+ units: str = "container",
151
+ **params,
152
+ ):
153
+ super().__init__(default=default, **params)
154
+ self.units = units
155
+ self.obj = obj
156
+ self.container = container
157
+
158
+ def hash_persistent(self) -> str:
159
+ """A hash function that avoids the PYTHONHASHSEED 'feature' which returns a different hash value each time the program is run"""
160
+ return hash_sha1(self)
161
+
162
+
163
+ class ResultVolume(param.Parameter):
139
164
  __slots__ = ["units", "obj"]
140
165
 
141
166
  def __init__(self, obj=None, default=None, units="container", **params):
bencher/video_writer.py CHANGED
@@ -1,8 +1,10 @@
1
- from bencher import gen_video_path
1
+ from bencher import gen_video_path, gen_image_path
2
+ from PIL import Image
3
+ import numpy as np
2
4
 
3
5
 
4
6
  class VideoWriter:
5
- def __init__(self, filename: str) -> None:
7
+ def __init__(self, filename: str = "vid") -> None:
6
8
  self.images = []
7
9
  self.filename = gen_video_path(filename)
8
10
 
@@ -12,6 +14,17 @@ class VideoWriter:
12
14
  def write(self, bitrate: int = 1500) -> str:
13
15
  import moviepy.video.io.ImageSequenceClip
14
16
 
17
+ # todo
18
+ # if len(self.images[0.shape) == 2:
19
+ # for i in range(len(self.images)):
20
+ # self.images[i] = np.expand_dims(self.images[i], 2)
21
+
15
22
  clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(self.images, fps=30)
16
- clip.write_videofile(self.filename, bitrate=f"{bitrate}k")
23
+ clip.write_videofile(self.filename, bitrate=f"{bitrate}k", logger=None)
17
24
  return self.filename
25
+
26
+
27
+ def add_image(np_array: np.ndarray, name: str = "img"):
28
+ filename = gen_image_path(name)
29
+ Image.fromarray(np_array).save(filename)
30
+ return filename
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: holobench
3
- Version: 1.3.3
3
+ Version: 1.3.5
4
4
  Summary: A package for benchmarking the performance of arbitrary functions
5
5
  Author-email: Austin Gregg-Smith <blooop@gmail.com>
6
6
  Requires-Python: >=3.10
@@ -21,7 +21,6 @@ Requires-Dist: strenum>=0.4.0,<=0.4.15
21
21
  Requires-Dist: scikit-learn>=1.2,<=1.3.2
22
22
  Requires-Dist: str2bool>=1.1,<=1.1
23
23
  Requires-Dist: scoop>=0.7.0,<=0.7.2.0
24
- Requires-Dist: ffmpeg-downloader>=0.3.0,<=0.3.0
25
24
  Requires-Dist: moviepy>=1.0.3,<=1.0.3
26
25
  Requires-Dist: black>=23,<=23.12.1 ; extra == "test"
27
26
  Requires-Dist: pylint>=2.16,<=3.0.3 ; extra == "test"
@@ -1,14 +1,14 @@
1
- bencher/__init__.py,sha256=l3s3a3hf7E6RciydXdHNuzzXPUUrqCs-imMnBrWqerU,1161
2
- bencher/bench_cfg.py,sha256=EMoANsz0bj4lioOCO_hlJNHH9-ciK042YAXvj2pk_dE,18244
1
+ bencher/__init__.py,sha256=lw9moEkY3rb3kQVS3_SM9L0LsOAXRSM1JUJ_mm16tMQ,1236
2
+ bencher/bench_cfg.py,sha256=g7gMQhzMEHBZzVfpBXhn5f0juCGLqK-nEBoSFKXAS2I,18743
3
3
  bencher/bench_plot_server.py,sha256=HnW6XpmARweMCd-koqzu1lxuj0gA4_fP-72D3Yfy-0M,4087
4
4
  bencher/bench_report.py,sha256=b9jLksrXzBhSmvI7KetO1i0hsHknE7qk4b4k0MGGtNw,10484
5
5
  bencher/bench_runner.py,sha256=TLJGn-NO4BBBZMG8W5E6u7IPyij67Yk3S4B29ONClnk,6049
6
- bencher/bencher.py,sha256=ACP0OjkYi4vGO3lfBTzV5RAMqci_-ErNuEyIlnO_48o,28609
6
+ bencher/bencher.py,sha256=jYOkqs5F6vIL9_KLygVgi0O_vj-xspBVlipduNMtt1Y,32012
7
7
  bencher/caching.py,sha256=AusaNrzGGlj5m6zcwcqnTn55Mam2mQdF--oqelO806M,1627
8
8
  bencher/job.py,sha256=Q2zpia95Ibukk8EeFq5IBbpo2PMRe7o5keelJCJlGnI,5927
9
- bencher/optuna_conversions.py,sha256=XwRUQjFZs_zCZo0iT4cudstorSSXThLKOv4o75IxBrw,5427
10
- bencher/utils.py,sha256=ddhTAXp9ciBhZBK5gLAJgpE6rUrMpnt4g7Wug1sSc_Q,4291
11
- bencher/video_writer.py,sha256=PlYLm6IBYG5MrK1J6U0ti2rvBzeMW2iXE4Pge7RsVII,523
9
+ bencher/optuna_conversions.py,sha256=9nLVPAydSQ8PyJlyhzs__Em6_Rx8l8Ld94UNJZxy6cY,5303
10
+ bencher/utils.py,sha256=oKUtD3Uw76n82ZeyWRBleneYKrZuuNE8pb7Gswlhwjc,5034
11
+ bencher/video_writer.py,sha256=L_RVrHU4C6hj9BhbEPelgPgtGZeHH4PYYW4CHjGXgJ0,937
12
12
  bencher/worker_job.py,sha256=FREi0yWQACFmH86R1j-LH72tALEFkKhLDmmoGQY9Jh4,1571
13
13
  bencher/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  bencher/example/benchmark_data.py,sha256=D9yUg_KKtqqEkAiLceodDwsv6sh7xEFWZNp6P6Y3pj4,6989
@@ -34,7 +34,7 @@ bencher/example/example_simple_cat.py,sha256=YFccE84g37U2M3ByWYIcGNLXWdW_ktJbbZv
34
34
  bencher/example/example_simple_float.py,sha256=X4vsH0F4fZAoO0EKB1xIzFMY0f0Wyk8LV2plPlSEsbI,1323
35
35
  bencher/example/example_strings.py,sha256=BdsEZgLT9mOxLkBKNHz2XpPwwe4SzNTdjnY1WVlOmNM,1570
36
36
  bencher/example/example_time_event.py,sha256=y1vpK7UDrObEu0Z1x3e4OQzvGCQ7pF5GZvpKLegMbYk,2158
37
- bencher/example/example_video.py,sha256=uI8tjF8BTTD9NsrBhK5rluBujLAaOaRAB5uXAvM1fZU,3387
37
+ bencher/example/example_video.py,sha256=w2NtsDL-afZWGlScrrHxr9vdCrxTvyzqOUhIeDOHjvU,4079
38
38
  bencher/example/example_workflow.py,sha256=00QnUuViMfX_PqzqkXmg1wPX6yAq7IS7mCL_RFKwrMM,6806
39
39
  bencher/example/experimental/example_bokeh_plotly.py,sha256=3jUKh8eKIAlpklKnp8UopIHhUDw1A0_5CwjeyTzbi7o,846
40
40
  bencher/example/experimental/example_hover_ex.py,sha256=qszw4FkIfqQkVviPSpmUoFOoi6PGotGbsc7Ojyx8EtU,1052
@@ -45,11 +45,11 @@ bencher/example/experimental/example_streams.py,sha256=rrTmcmxDlirGoyTbJ4LT4fBIA
45
45
  bencher/example/experimental/example_template.py,sha256=XdIVS9RtLdE5GNnerWiZMXvP7n17lzuc_YTLqJTwb6Q,1172
46
46
  bencher/example/experimental/example_updates.py,sha256=rF4UgWY-CW6ohNtOpQklTuwbwVRvEM5j6edZOiMkspQ,1835
47
47
  bencher/example/experimental/example_vector.py,sha256=3o_1dA4dc2HL6uIEvDAcvLPVJB8jgkq1QZ3BQIL-LEo,3118
48
- bencher/example/meta/example_meta.py,sha256=OpresXooPvkSVI3mfExqiATyGvd3o5x-dmIjhTH5Zf4,5734
48
+ bencher/example/meta/example_meta.py,sha256=P71Q-3G8B44DYaZQe5eFmFxUsjbViSat3DcUvgdSSuw,5605
49
49
  bencher/example/meta/example_meta_cat.py,sha256=YKVUiZ7M1tFFYgUTVQZeOe-1bnmxOjLdWy3nmCoyEe0,693
50
50
  bencher/example/meta/example_meta_float.py,sha256=f3OcORsRUt9Bnd1M1hOjmgxulxcalwdQHSQ0Psx1rY8,650
51
51
  bencher/example/meta/example_meta_levels.py,sha256=O77D4gAGYf7uZo7-Kj2ZwyNmpnc4paoQXE_DQtKKWKo,1488
52
- bencher/example/optuna/example_optuna.py,sha256=EYxRMHCRvy0vB-ObQlyi6ZJHoZ8QvnQQrDJWyuS_lvc,2369
52
+ bencher/example/optuna/example_optuna.py,sha256=-RIuDrdPjfXz1c1hOAmWeJNdmGICiWnyJfAavRsiMuk,2370
53
53
  bencher/example/shelved/example_float2D_scatter.py,sha256=z8ranMq8IcJ1yoVSFDncp3gw-yWG7X9lXLimXKpy5Ks,3372
54
54
  bencher/example/shelved/example_float3D_cone.py,sha256=T3-IapccLYX3BM9sGDyOTLhZVEmzkeMsXzQMT5msnNQ,2966
55
55
  bencher/example/shelved/example_kwargs.py,sha256=Bgxkd7qeHdySBE24amdP-VNFRRgK_enyzprlxBwY9Ko,2461
@@ -57,18 +57,18 @@ bencher/plotting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
57
57
  bencher/plotting/plot_filter.py,sha256=Zff02hEcRffiqDEoXUHVZQJK5kW4HbMxe2GYCrxI8jg,4688
58
58
  bencher/plotting/plt_cnt_cfg.py,sha256=BkiAsgHm35Mqb5OsjULGVK0Q6pGZ0WSsJxxwSOrbaQs,3124
59
59
  bencher/results/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
- bencher/results/bench_result.py,sha256=O0RxxUoudT43zukIKEmwaj8Q156UrEfwyj8NGFFwI0c,2797
61
- bencher/results/bench_result_base.py,sha256=LILzZ5R5p0xEcGXsWN3ohRKhpC45OHLD9-K635J4kRQ,15412
60
+ bencher/results/bench_result.py,sha256=NiJ8UIYrw5QBksltIHAOh-4CaIMYI8YA-cEcWgfwZ70,2838
61
+ bencher/results/bench_result_base.py,sha256=-c46om4Gulzxn3PPvQAsQF9qzT7rQLtX6hsO65f9N2A,15767
62
62
  bencher/results/float_formatter.py,sha256=sX6HNCyaXdHDxC8ybVUHwCJ3qOKbPUkBOplVIHtKWjM,1746
63
- bencher/results/holoview_result.py,sha256=dsXZiTlQ6U9U6pSBiLAMUdYXzsW-VLEpZ2bLDrdfvZU,20158
64
- bencher/results/optuna_result.py,sha256=704l1eFJUQGTmnTaj2pIJ9ocRehLgu4PwMYmJU2rY9w,12399
65
- bencher/results/panel_result.py,sha256=5oMY0KDRoGK_3LoUJB-pRy9b0QMowVvu7hR6f2-0P8c,3647
63
+ bencher/results/holoview_result.py,sha256=nfXYTaGQkXwLqJ_gEB3TYJxHfKAQCN1E60D9Tfbkxos,22254
64
+ bencher/results/optuna_result.py,sha256=jtsWJGdCS0L98EzxTxXU_AyarCL5CkXRLOVuSvs048M,13437
65
+ bencher/results/panel_result.py,sha256=SpVHHdTdlNHh1pGcK3DYLw6BClDRJ_37TNTkicnErTU,3936
66
66
  bencher/results/plotly_result.py,sha256=wkgfL38qJp6RviekXBYpNPeU4HCf0nbtKDAhu5QZhUg,2132
67
- bencher/variables/inputs.py,sha256=HYWEK75qfzk86dWvZbb6TeZr6yEvXgXILdddAqGuvEs,6392
68
- bencher/variables/parametrised_sweep.py,sha256=96fLNjq1x7tGSwGCVshR3_LK9PRHhLipj8pbJ5umbnA,7029
69
- bencher/variables/results.py,sha256=yXdLjfGPSerWhipw_GDZJpBB8KQgCqcdreb8WjIeah8,5119
67
+ bencher/variables/inputs.py,sha256=XtUko3qNYB1xk7fwM9teVGRU0MNCW673n2teGtoyFGU,6393
68
+ bencher/variables/parametrised_sweep.py,sha256=3ioxqm8xg9WYIH-eRFRhDSn_YphGD-269gZ_FaxuEv8,7029
69
+ bencher/variables/results.py,sha256=omENIr_Y3RxRG8sr4RQKD1Y_vTyMJUoA7P-fV1uSX5Y,6015
70
70
  bencher/variables/sweep_base.py,sha256=I1LEeG1y5Jsw0a-Ik03t0tSzcfENht2GmBECJ3KNs28,6559
71
71
  bencher/variables/time.py,sha256=Le7s8_oUYJD4wCqwQw-a_FRDpYQOi8CqMbGYsBF07jg,2860
72
- holobench-1.3.3.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
73
- holobench-1.3.3.dist-info/METADATA,sha256=0J2iK-aBJK3NvwuyrHVyQaElPTfzZbwDCnsRZzJOGKE,4994
74
- holobench-1.3.3.dist-info/RECORD,,
72
+ holobench-1.3.5.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
73
+ holobench-1.3.5.dist-info/METADATA,sha256=yzGpIvCdTY9riHJHhC9OGAKymmg0LbbQ7AwheTwBhXo,4946
74
+ holobench-1.3.5.dist-info/RECORD,,