holobench 1.40.0__py3-none-any.whl → 1.41.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.
CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.3.10]
9
+
10
+ Before changelogs
bencher/bench_cfg.py CHANGED
@@ -6,17 +6,14 @@ import logging
6
6
  from typing import List
7
7
 
8
8
  import param
9
- from str2bool import str2bool
10
9
  import panel as pn
11
-
10
+ from datetime import datetime
12
11
 
13
12
  from bencher.variables.sweep_base import hash_sha1, describe_variable
14
13
  from bencher.variables.time import TimeSnapshot, TimeEvent
15
14
  from bencher.variables.results import OptDir
16
15
  from bencher.job import Executors
17
- from datetime import datetime
18
-
19
- # from bencher.results.bench_result import BenchResult
16
+ from bencher.results.laxtex_result import to_latex
20
17
 
21
18
 
22
19
  class BenchPlotSrvCfg(param.Parameterized):
@@ -199,11 +196,8 @@ class BenchRunCfg(BenchPlotSrvCfg):
199
196
 
200
197
  parser.add_argument(
201
198
  "--nightly",
202
- type=lambda b: bool(str2bool(b)),
203
- nargs="?",
204
- const=False,
205
- default=False,
206
- help="turn on nightly benchmarking",
199
+ action="store_true",
200
+ help="Turn on nightly benchmarking",
207
201
  )
208
202
 
209
203
  parser.add_argument(
@@ -344,13 +338,32 @@ class BenchCfg(BenchRunCfg):
344
338
  def inputs_as_str(self) -> List[str]:
345
339
  return [i.name for i in self.input_vars]
346
340
 
347
- def describe_sweep(self, width: int = 800, accordion=True) -> pn.pane.Markdown:
341
+ def to_latex(self):
342
+ return to_latex(self)
343
+
344
+ def describe_sweep(self, width: int = 800, accordion=True) -> pn.pane.Markdown | pn.Column:
348
345
  """Produce a markdown summary of the sweep settings"""
349
346
 
347
+ latex = self.to_latex()
350
348
  desc = pn.pane.Markdown(self.describe_benchmark(), width=width)
351
349
  if accordion:
352
- return pn.Accordion(("Data Collection Parameters", desc))
353
- return desc
350
+ desc = pn.Accordion(("Expand Full Data Collection Parameters", desc))
351
+
352
+ sentence = self.sweep_sentence()
353
+ if latex is not None:
354
+ return pn.Column(sentence, latex, desc)
355
+ return pn.Column(sentence, latex, desc)
356
+
357
+ def sweep_sentence(self):
358
+ inputs = " by ".join([iv.name for iv in self.all_vars])
359
+
360
+ all_vars_lens = [len(iv.values()) for iv in reversed(self.all_vars)]
361
+ if len(all_vars_lens) == 1:
362
+ all_vars_lens.append(1)
363
+ result_sizes = "x".join([str(iv) for iv in all_vars_lens])
364
+ results = ", ".join([rv.name for rv in self.result_vars])
365
+
366
+ return f"Sweeping {inputs} to generate a {result_sizes} result dataframe containing {results}. "
354
367
 
355
368
  def describe_benchmark(self) -> str:
356
369
  """Generate a string summary of the inputs and results from a BenchCfg
bencher/caching.py CHANGED
@@ -3,9 +3,6 @@ from diskcache import Cache
3
3
  from bencher.variables.parametrised_sweep import ParametrizedSweep
4
4
  from bencher.utils import hash_sha1
5
5
  import logging
6
- from sortedcontainers import SortedDict
7
-
8
- # from job import job,JobCache,JobFunctionCache
9
6
 
10
7
 
11
8
  class CachedParams(ParametrizedSweep):
@@ -20,7 +17,7 @@ class CachedParams(ParametrizedSweep):
20
17
  self.cache.clear()
21
18
 
22
19
  def kwargs_to_hash_key(self, **kwargs):
23
- return tuple(SortedDict(kwargs).items())
20
+ return tuple(sorted(kwargs.items(), key=lambda item: str(item[0])))
24
21
 
25
22
  def in_cache(self, **kwargs):
26
23
  self.update_params_from_kwargs(**kwargs)
@@ -0,0 +1,60 @@
1
+ import bencher as bch
2
+
3
+ from bencher.example.example_image import BenchPolygons
4
+
5
+
6
+ class BenchComposableContainerImage(BenchPolygons):
7
+ compose_method = bch.EnumSweep(bch.ComposeType)
8
+ labels = bch.BoolSweep()
9
+ num_frames = bch.IntSweep(default=5, bounds=[1, 100])
10
+
11
+ polygon_vid = bch.ResultVideo()
12
+
13
+ def __call__(self, **kwargs):
14
+ self.update_params_from_kwargs(**kwargs)
15
+ var_name = None
16
+ var_value = None
17
+
18
+ if self.labels:
19
+ var_name = "sides"
20
+ var_value = self.sides
21
+ vr = bch.ComposableContainerVideo()
22
+ for i in range(self.num_frames):
23
+ res = super().__call__(start_angle=i)
24
+ print(res)
25
+ vr.append(res["polygon"])
26
+ self.polygon_vid = vr.to_video(
27
+ bch.RenderCfg(
28
+ compose_method=self.compose_method,
29
+ var_name=var_name,
30
+ var_value=var_value,
31
+ max_frame_duration=1.0 / 20.0,
32
+ )
33
+ )
34
+ return self.get_results_values_as_dict()
35
+
36
+
37
+ def example_composable_container_image(
38
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
39
+ ) -> bch.Bench:
40
+ bench = BenchComposableContainerImage().to_bench(run_cfg, report)
41
+ # bench.add_plot_callback(bch.BenchResult.to_panes)
42
+ # bench.add_plot_callback(bch.BenchResult.to_video_grid, result_types=(bch.ResultVideo))
43
+ # bench.add_plot_callback(bch.BenchResult.to_video_summary, result_types=(bch.ResultVideo))
44
+ # bench.plot_sweep(input_vars=["compose_method", "labels"])
45
+
46
+ bench.plot_sweep(input_vars=["compose_method"])
47
+
48
+ # bench.compose_
49
+ # bench.plot_sweep(
50
+ # input_vars=[bch.p("num_frames", [2, 8, 20])],
51
+ # const_vars=dict(compose_method=bch.ComposeType.sequence),
52
+ # )
53
+
54
+ return bench
55
+
56
+
57
+ if __name__ == "__main__":
58
+ ex_run_cfg = bch.BenchRunCfg()
59
+ ex_composable_image = example_composable_container_image(ex_run_cfg)
60
+ ex_composable_image.report.show()
@@ -0,0 +1,49 @@
1
+ import bencher as bch
2
+ from bencher.example.example_composable_container_image import BenchComposableContainerImage
3
+
4
+
5
+ class BenchComposableContainerVideo(bch.ParametrizedSweep):
6
+ unequal_length = bch.BoolSweep()
7
+ compose_method = bch.EnumSweep(bch.ComposeType)
8
+ labels = bch.BoolSweep()
9
+ polygon_vid = bch.ResultVideo()
10
+
11
+ def __call__(self, **kwargs):
12
+ self.update_params_from_kwargs(**kwargs)
13
+ vr = bch.ComposableContainerVideo()
14
+ for i in range(3, 5):
15
+ num_frames = i * 10 if self.unequal_length else 5
16
+ res = BenchComposableContainerImage().__call__(
17
+ compose_method=bch.ComposeType.sequence, sides=i, num_frames=num_frames
18
+ )
19
+ vr.append(res["polygon_vid"])
20
+
21
+ self.polygon_vid = vr.to_video(bch.RenderCfg(compose_method=kwargs.get("compose_method")))
22
+ return self.get_results_values_as_dict()
23
+
24
+
25
+ def example_composable_container_video(
26
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
27
+ ) -> bch.Bench:
28
+ bench = BenchComposableContainerVideo().to_bench(run_cfg, report)
29
+
30
+ bench.result_vars = ["polygon_vid"]
31
+ bench.add_plot_callback(bch.BenchResult.to_panes)
32
+ bench.add_plot_callback(bch.BenchResult.to_video_grid, result_types=(bch.ResultVideo))
33
+ bench.add_plot_callback(bch.BenchResult.to_video_summary, result_types=(bch.ResultVideo))
34
+ bench.plot_sweep(input_vars=["compose_method", "labels"], const_vars=dict(unequal_length=True))
35
+
36
+ res = bench.plot_sweep(
37
+ input_vars=[],
38
+ const_vars=dict(unequal_length=False, compose_method=bch.ComposeType.sequence),
39
+ plot_callbacks=False,
40
+ )
41
+
42
+ bench.report.append(res.to_video_grid())
43
+
44
+ return bench
45
+
46
+
47
+ if __name__ == "__main__":
48
+ ex_run_cfg = bch.BenchRunCfg()
49
+ example_composable_container_video(ex_run_cfg).report.show()
@@ -1,7 +1,7 @@
1
1
  import bencher as bch
2
2
  import numpy as np
3
3
  import math
4
- import matplotlib.pyplot as plt
4
+ from PIL import Image, ImageDraw
5
5
 
6
6
 
7
7
  def polygon_points(radius: float, sides: int, start_angle: float):
@@ -16,7 +16,6 @@ class BenchPolygons(bch.ParametrizedSweep):
16
16
  sides = bch.IntSweep(default=3, bounds=(3, 7))
17
17
  radius = bch.FloatSweep(default=1, bounds=(0.2, 1))
18
18
  linewidth = bch.FloatSweep(default=1, bounds=(1, 10))
19
- linestyle = bch.StringSweep(["solid", "dashed", "dotted"])
20
19
  color = bch.StringSweep(["red", "green", "blue"])
21
20
  start_angle = bch.FloatSweep(default=0, bounds=[0, 360])
22
21
  polygon = bch.ResultImage()
@@ -26,33 +25,30 @@ class BenchPolygons(bch.ParametrizedSweep):
26
25
  def __call__(self, **kwargs):
27
26
  self.update_params_from_kwargs(**kwargs)
28
27
  points = polygon_points(self.radius, self.sides, self.start_angle)
29
- # self.hmap = hv.Curve(points)
30
- self.polygon = self.points_to_polygon_png(points, bch.gen_image_path("polygon"))
28
+ filepath = bch.gen_image_path("polygon")
29
+ self.polygon = self.points_to_polygon_png(points, filepath)
30
+ # Verify filepath is being returned
31
+ assert isinstance(self.polygon, str), f"Expected string filepath, got {type(self.polygon)}"
31
32
 
32
33
  self.side_length = 2 * self.radius * math.sin(math.pi / self.sides)
33
34
  self.area = (self.sides * self.side_length**2) / (4 * math.tan(math.pi / self.sides))
34
35
  return super().__call__()
35
36
 
36
37
  def points_to_polygon_png(self, points: list[float], filename: str):
37
- """Draw a closed polygon and save to png"""
38
- fig = plt.figure(frameon=False)
39
- ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0], frameon=False)
40
- ax.set_axis_off()
41
- ax.plot(
42
- [p[0] for p in points],
43
- [p[1] for p in points],
44
- linewidth=self.linewidth,
45
- linestyle=self.linestyle,
46
- color=self.color,
47
- )
48
- ax.set_xlim(-1, 1)
49
- ax.set_ylim(-1, 1)
38
+ """Draw a closed polygon and save to png using PIL"""
39
+ size = 300
40
+ img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
41
+ draw = ImageDraw.Draw(img)
42
+
43
+ # Scale points to image size (from [-1,1] to [0,size])
44
+ scaled_points = [(((p[0] + 1) * size / 2), ((1 - p[1]) * size / 2)) for p in points]
50
45
 
51
- ax.set_aspect("equal")
52
- fig.add_axes(ax)
53
- fig.savefig(filename, dpi=30)
46
+ # Draw polygon outline
47
+ draw.line(scaled_points, fill=self.color, width=int(self.linewidth))
54
48
 
55
- return filename
49
+ img.save(filename, "PNG")
50
+ # Explicitly return the filename string
51
+ return str(filename)
56
52
 
57
53
 
58
54
  def example_image(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None) -> bch.Bench:
@@ -1,7 +1,7 @@
1
1
  import bencher as bch
2
2
  import numpy as np
3
3
  import math
4
- import matplotlib.pyplot as plt
4
+ from PIL import Image, ImageDraw
5
5
 
6
6
 
7
7
  def polygon_points(radius: float, sides: int, start_angle: float):
@@ -28,36 +28,32 @@ class BenchPolygons(bch.ParametrizedSweep):
28
28
  def __call__(self, **kwargs):
29
29
  self.update_params_from_kwargs(**kwargs)
30
30
  points = polygon_points(self.radius, self.sides, self.start_angle)
31
- # self.hmap = hv.Curve(points)
32
- self.polygon = self.points_to_polygon_png(points, bch.gen_image_path("polygon"), dpi=30)
31
+ filepath = bch.gen_image_path("polygon")
32
+ self.polygon = self.points_to_polygon_png(points, filepath, dpi=30)
33
33
  self.polygon_small = self.points_to_polygon_png(
34
34
  points, bch.gen_image_path("polygon"), dpi=10
35
35
  )
36
+ # Verify filepaths are being returned
37
+ assert isinstance(self.polygon, str), f"Expected string filepath, got {type(self.polygon)}"
38
+ assert isinstance(self.polygon_small, str), (
39
+ f"Expected string filepath, got {type(self.polygon_small)}"
40
+ )
36
41
 
37
42
  self.side_length = 2 * self.radius * math.sin(math.pi / self.sides)
38
43
  self.area = (self.sides * self.side_length**2) / (4 * math.tan(math.pi / self.sides))
39
44
  return super().__call__()
40
45
 
41
46
  def points_to_polygon_png(self, points: list[float], filename: str, dpi):
42
- """Draw a closed polygon and save to png"""
43
- fig = plt.figure(frameon=False)
44
- ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0], frameon=False)
45
- ax.set_axis_off()
46
- ax.plot(
47
- [p[0] for p in points],
48
- [p[1] for p in points],
49
- linewidth=self.linewidth,
50
- linestyle=self.linestyle,
51
- color=self.color,
52
- )
53
- ax.set_xlim(-1, 1)
54
- ax.set_ylim(-1, 1)
47
+ """Draw a closed polygon and save to png using PIL"""
48
+ size = int(100 * (dpi / 30))
49
+ img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
50
+ draw = ImageDraw.Draw(img)
55
51
 
56
- ax.set_aspect("equal")
57
- fig.add_axes(ax)
58
- fig.savefig(filename, dpi=dpi)
52
+ scaled_points = [(((p[0] + 1) * size / 2), ((1 - p[1]) * size / 2)) for p in points]
53
+ draw.line(scaled_points, fill=self.color, width=int(self.linewidth))
59
54
 
60
- return filename
55
+ img.save(filename, "PNG")
56
+ return str(filename)
61
57
 
62
58
 
63
59
  def example_image_vid_sequential1(
@@ -1,9 +1,24 @@
1
1
  import bencher as bch
2
2
  import numpy as np
3
- import matplotlib.pyplot as plt
3
+ from PIL import Image
4
+ import colorcet as cc
5
+ import numpy.typing as npt
6
+
7
+
8
+ def apply_colormap(data: npt.NDArray) -> npt.NDArray:
9
+ """Apply a perceptually uniform colormap to the data"""
10
+ # Normalize data to [0, 1]
11
+ normalized = (data - data.min()) / (data.max() - data.min())
12
+ # Convert hex colors to RGB values using numpy's frombuffer
13
+ colors = np.array(
14
+ [np.frombuffer(bytes.fromhex(c.lstrip("#")), dtype=np.uint8) for c in cc.rainbow]
15
+ )
16
+ # Map normalized values to colormap indices
17
+ indices = (normalized * (len(colors) - 1)).astype(int)
18
+ # Create RGB array from the colormap
19
+ return colors[indices]
4
20
 
5
21
 
6
- # code from https://ipython-books.github.io/124-simulating-a-partial-differential-equation-reaction-diffusion-systems-and-turing-patterns/
7
22
  class TuringPattern(bch.ParametrizedSweep):
8
23
  alpha = bch.FloatSweep(default=2.8e-4, bounds=(2e-4, 5e-3))
9
24
  beta = bch.FloatSweep(default=5e-3, bounds=(1e-3, 9e-3))
@@ -17,6 +32,7 @@ class TuringPattern(bch.ParametrizedSweep):
17
32
  video = bch.ResultVideo()
18
33
  score = bch.ResultVar()
19
34
  img = bch.ResultImage()
35
+ img_extracted = bch.ResultImage()
20
36
 
21
37
  def laplacian(self, Z, dx):
22
38
  Ztop = Z[0:-2, 1:-1]
@@ -49,28 +65,28 @@ class TuringPattern(bch.ParametrizedSweep):
49
65
  def __call__(self, **kwargs):
50
66
  self.update_params_from_kwargs(**kwargs)
51
67
 
52
- n = int(self.time / self.dt) # number of iterations
53
- dx = 2.0 / self.size # space step
68
+ n = int(self.time / self.dt)
69
+ dx = 2.0 / self.size
54
70
 
55
71
  U = np.random.rand(self.size, self.size)
56
72
  V = np.random.rand(self.size, self.size)
57
73
 
58
- fig, ax = plt.subplots(frameon=False, figsize=(2, 2))
59
- fig.set_tight_layout(True)
60
- ax.set_axis_off()
61
74
  vid_writer = bch.VideoWriter()
62
75
  for i in range(n):
63
76
  self.update(U, V, dx)
64
77
  if i % 500 == 0:
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.img = bch.add_image(rgb)
71
-
78
+ # Apply colormap to create RGB image
79
+ rgb = apply_colormap(U)
80
+ # Create PIL image with alpha channel
81
+ img = Image.fromarray(rgb, "RGB").convert("RGBA")
82
+ img = img.resize((200, 200), Image.Resampling.LANCZOS)
83
+ rgb_alpha = np.array(img)
84
+ vid_writer.append(rgb_alpha)
85
+
86
+ self.img = bch.add_image(rgb_alpha)
72
87
  self.video = vid_writer.write()
73
-
88
+ self.img_extracted = bch.video_writer.VideoWriter.extract_frame(self.video)
89
+ print("img path", self.img_extracted)
74
90
  self.score = self.alpha + self.beta
75
91
  return super().__call__()
76
92
 
@@ -109,8 +125,8 @@ def example_video_tap(
109
125
  if __name__ == "__main__":
110
126
  run_cfg_ex = bch.BenchRunCfg()
111
127
  run_cfg_ex.level = 2
112
- run_cfg_ex.cache_samples = True
113
- run_cfg_ex.only_hash_tag = True
128
+ # run_cfg_ex.cache_samples = True
129
+ # run_cfg_ex.only_hash_tag = True
114
130
 
115
131
  # example_video(run_cfg_ex).report.show()
116
132
  example_video_tap(run_cfg_ex).report.show()
@@ -1,6 +1,5 @@
1
1
  # THIS IS NOT A WORKING EXAMPLE YET
2
2
  # pylint: disable=duplicate-code
3
- import hvplot
4
3
  import bencher as bch
5
4
  from bencher import ExampleBenchCfgIn, ExampleBenchCfgOut, bench_function
6
5
 
@@ -35,5 +34,5 @@ if __name__ == "__main__":
35
34
  ),
36
35
  )
37
36
 
38
- hvexplorer = hvplot.explorer(bench_out.get_dataframe())
39
- hvexplorer.show()
37
+ bench.report.append(bench_out.to_explorer())
38
+ bench.report.show()
@@ -0,0 +1,12 @@
1
+ import bencher as bch
2
+ from bencher.example.meta.example_meta import BenchableObject
3
+
4
+ run_cfg = bch.BenchRunCfg()
5
+ run_cfg.repeats = 20
6
+ run_cfg.level = 4
7
+ bench = BenchableObject().to_bench(run_cfg)
8
+ res = bench.plot_sweep(
9
+ input_vars=["float1", "noisy", "noise_distribution"], result_vars=["distance", "sample_noise"]
10
+ )
11
+
12
+ bench.report.show()
@@ -49,6 +49,8 @@ if __name__ == "__main__":
49
49
  "/workspaces/bencher/bencher/example/inputs_1D/example_1_in_2_out_repeats.py", "1D"
50
50
  )
51
51
 
52
- convert_example_to_jupyter_notebook(
53
- "/workspaces/bencher/bencher/example/example_simple_float.py", "1D"
54
- )
52
+ # todo, enable
53
+ # convert_example_to_jupyter_notebook(
54
+ # "/workspaces/bencher/bencher/example/example_composable_container_video.py",
55
+ # "Media",
56
+ # )
@@ -39,7 +39,7 @@ class BenchMetaGen(bch.ParametrizedSweep):
39
39
  inputs_vars_float = [
40
40
  "float1",
41
41
  "float2",
42
- "float3",
42
+ bch.p("float3", max_level=3),
43
43
  "sigma",
44
44
  ]
45
45
 
@@ -107,10 +107,9 @@ def example_meta(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
107
107
  description="""## All Combinations of Variable Sweeps and Resulting Plots
108
108
  This uses bencher to display all the combinations of plots bencher is able to produce""",
109
109
  input_vars=[
110
- bch.p("float_vars", [0, 1, 2, 3]),
110
+ bch.p("float_vars", [0, 1]),
111
111
  "categorical_vars",
112
112
  bch.p("sample_with_repeats", [1, 20]),
113
- # "sample_over_time",
114
113
  ],
115
114
  const_vars=[
116
115
  # BenchMeta.param.float_vars.with_const(1),
@@ -119,6 +118,31 @@ This uses bencher to display all the combinations of plots bencher is able to pr
119
118
  # BenchMeta.param.sample_over_time.with_const(True),
120
119
  ],
121
120
  )
121
+ bench.plot_sweep(
122
+ title="Meta Bench",
123
+ description="""## All Combinations of Variable Sweeps and Resulting Plots
124
+ This uses bencher to display all the combinations of plots bencher is able to produce""",
125
+ input_vars=[
126
+ bch.p("float_vars", [2, 3]),
127
+ "categorical_vars",
128
+ ],
129
+ )
130
+
131
+ # bench.plot_sweep(
132
+ # title="Meta Bench",
133
+ # description="""## All Combinations of Variable Sweeps and Resulting Plots
134
+ # This uses bencher to display all the combinations of plots bencher is able to produce""",
135
+ # input_vars=[
136
+ # bch.p("float_vars", [2, 3]),
137
+ # "categorical_vars",
138
+ # ],
139
+ # const_vars=[
140
+ # dict(level=3)
141
+ # # BenchMeta.param.sample_with_repeats.with_const(2),
142
+ # # BenchMeta.param.categorical_vars.with_const(2),
143
+ # # BenchMeta.param.sample_over_time.with_const(True),
144
+ # ],
145
+ # )
122
146
 
123
147
  return bench
124
148
 
bencher/job.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
  from typing import Callable
3
- from sortedcontainers import SortedDict
4
3
  import logging
5
4
  from diskcache import Cache
6
5
  from concurrent.futures import Future, ProcessPoolExecutor
@@ -11,7 +10,6 @@ from enum import auto
11
10
  try:
12
11
  from scoop import futures as scoop_future_executor
13
12
  except ImportError as e:
14
- logging.warning(e.msg)
15
13
  scoop_future_executor = None
16
14
 
17
15
 
@@ -23,7 +21,7 @@ class Job:
23
21
  self.function = function
24
22
  self.job_args = job_args
25
23
  if job_key is None:
26
- self.job_key = hash_sha1(tuple(SortedDict(self.job_args).items()))
24
+ self.job_key = hash_sha1(tuple(sorted(self.job_args.items())))
27
25
  else:
28
26
  self.job_key = job_key
29
27
  self.tag = tag
@@ -53,6 +53,7 @@ class BenchResult(PlotlyResult, HoloviewResult, HvplotResult, VideoSummaryResult
53
53
  self,
54
54
  plot_list: List[callable] = None,
55
55
  remove_plots: List[callable] = None,
56
+ default_container=pn.Column,
56
57
  **kwargs,
57
58
  ) -> List[pn.panel]:
58
59
  self.plt_cnt_cfg.print_debug = False
@@ -67,7 +68,7 @@ class BenchResult(PlotlyResult, HoloviewResult, HvplotResult, VideoSummaryResult
67
68
 
68
69
  kwargs = self.set_plot_size(**kwargs)
69
70
 
70
- row = EmptyContainer(pn.Row())
71
+ row = EmptyContainer(default_container())
71
72
  for plot_callback in plot_list:
72
73
  if self.plt_cnt_cfg.print_debug:
73
74
  print(f"checking: {plot_callback.__name__}")
@@ -321,7 +321,7 @@ class BenchResultBase(OptunaResult):
321
321
  **kwargs,
322
322
  ) -> Optional[pn.Row]:
323
323
  if hv_dataset is None:
324
- hv_dataset = self.to_hv_dataset()
324
+ hv_dataset = self.to_hv_dataset(reduce=reduce)
325
325
 
326
326
  if pane_collection is None:
327
327
  pane_collection = pn.Row()
@@ -333,7 +333,7 @@ class BenchResultBase(OptunaResult):
333
333
  if result_types is None or isinstance(rv, result_types):
334
334
  row.append(
335
335
  self.to_panes_multi_panel(
336
- self.to_hv_dataset(reduce=reduce, result_var=rv),
336
+ hv_dataset,
337
337
  rv,
338
338
  plot_callback=partial(plot_callback, **kwargs),
339
339
  target_dimension=target_dimension,
@@ -3,7 +3,7 @@ import numpy as np
3
3
  from copy import deepcopy
4
4
  from pathlib import Path
5
5
  from dataclasses import dataclass
6
- from moviepy.editor import (
6
+ from moviepy import (
7
7
  ImageClip,
8
8
  CompositeVideoClip,
9
9
  clips_array,
@@ -11,22 +11,43 @@ from moviepy.editor import (
11
11
  VideoClip,
12
12
  VideoFileClip,
13
13
  )
14
- from moviepy.video.fx.margin import margin
15
14
 
16
15
  from bencher.results.composable_container.composable_container_base import (
17
16
  ComposableContainerBase,
18
17
  ComposeType,
19
18
  )
20
19
  from bencher.video_writer import VideoWriter
20
+ from moviepy import vfx
21
21
 
22
22
 
23
23
  @dataclass()
24
24
  class RenderCfg:
25
+ """Configuration class for video rendering options.
26
+
27
+ This class controls how videos and images are composed and rendered together.
28
+ It provides options for timing, layout, appearance, and labeling of the output.
29
+
30
+ Attributes:
31
+ compose_method (ComposeType): Method to compose multiple clips (sequence, right, down, overlay).
32
+ Defaults to ComposeType.sequence.
33
+ var_name (str, optional): Variable name for labeling. Defaults to None.
34
+ var_value (str, optional): Variable value for labeling. Defaults to None.
35
+ background_col (tuple[int, int, int]): RGB color for background. Defaults to white (255, 255, 255).
36
+ duration (float): Target duration for the composed video in seconds. Defaults to 10.0.
37
+ default_duration (float): Fallback duration when duration is None. Defaults to 10.0.
38
+ duration_target (bool): If True, tries to match target duration while respecting frame
39
+ duration constraints. If False, uses exact duration. Defaults to True.
40
+ min_frame_duration (float): Minimum duration for each frame in seconds. Defaults to 1/30.
41
+ max_frame_duration (float): Maximum duration for each frame in seconds. Defaults to 2.0.
42
+ margin (int): Margin size in pixels to add around clips. Defaults to 0.
43
+ """
44
+
25
45
  compose_method: ComposeType = ComposeType.sequence
26
46
  var_name: str = None
27
47
  var_value: str = None
28
48
  background_col: tuple[int, int, int] = (255, 255, 255)
29
49
  duration: float = 10.0
50
+ default_duration: float = 10.0
30
51
  duration_target: bool = True
31
52
  min_frame_duration: float = 1.0 / 30
32
53
  max_frame_duration: float = 2.0
@@ -69,7 +90,9 @@ class ComposableContainerVideo(ComposableContainerBase):
69
90
  def calculate_duration(self, frames, render_cfg: RenderCfg):
70
91
  if render_cfg.duration_target:
71
92
  # calculate duration based on fps constraints
72
- duration = 10.0 if render_cfg.duration is None else render_cfg.duration
93
+ duration = (
94
+ render_cfg.default_duration if render_cfg.duration is None else render_cfg.duration
95
+ )
73
96
  frame_duration = duration / frames
74
97
  if render_cfg.min_frame_duration is not None:
75
98
  frame_duration = max(frame_duration, render_cfg.min_frame_duration)
@@ -77,7 +100,10 @@ class ComposableContainerVideo(ComposableContainerBase):
77
100
  frame_duration = min(frame_duration, render_cfg.max_frame_duration)
78
101
  duration = frame_duration * frames
79
102
  else:
80
- duration = render_cfg.duration
103
+ if render_cfg.duration is None:
104
+ duration = render_cfg.default_duration
105
+ else:
106
+ duration = render_cfg.duration
81
107
  frame_duration = duration / float(frames)
82
108
 
83
109
  print("max_frame_duration", render_cfg.max_frame_duration)
@@ -111,8 +137,8 @@ class ComposableContainerVideo(ComposableContainerBase):
111
137
  case ComposeType.right | ComposeType.down:
112
138
  for i in range(len(self.container)):
113
139
  self.container[i] = self.extend_clip(self.container[i], max_duration)
114
- self.container[i] = margin(
115
- self.container[i], top=render_cfg.margin, color=render_cfg.background_col
140
+ self.container[i] = self.container[i].with_effects(
141
+ [vfx.Margin(top=render_cfg.margin, color=render_cfg.background_col)]
116
142
  )
117
143
 
118
144
  if render_cfg.compose_method == ComposeType.right:
@@ -126,13 +152,14 @@ class ComposableContainerVideo(ComposableContainerBase):
126
152
  out = concatenate_videoclips(
127
153
  self.container, bg_color=render_cfg.background_col, method="compose"
128
154
  )
129
- # case ComposeType.overlay:
130
- # for i in range(len(self.container)):
131
- # self.container[i].alpha = 1./len(self.container)
132
- # out = CompositeVideoClip(self.container, bg_color=render_cfg.background_col)
133
- # # out.duration = fps
155
+ case ComposeType.overlay:
156
+ for i in range(len(self.container)):
157
+ self.container[i] = self.container[i].with_opacity(1.0 / len(self.container))
158
+ out = CompositeVideoClip(self.container, bg_color=render_cfg.background_col)
134
159
  case _:
135
- raise RuntimeError("This compose type is not supported")
160
+ raise RuntimeError(
161
+ f"This compose type is not supported: {render_cfg.compose_method}"
162
+ )
136
163
 
137
164
  label = self.label_formatter(render_cfg.var_name, render_cfg.var_value)
138
165
  if label is not None:
@@ -154,14 +154,14 @@ class HoloviewResult(PanelResult):
154
154
  tap_var = [tap_var]
155
155
 
156
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
157
+ line_cb = self.to_line_ds
158
158
  else:
159
- heatmap_cb = partial(
159
+ line_cb = partial(
160
160
  self.to_line_tap_ds, result_var_plots=tap_var, container=tap_container
161
161
  )
162
162
 
163
163
  return self.filter(
164
- heatmap_cb,
164
+ line_cb,
165
165
  float_range=VarRange(1, 1),
166
166
  cat_range=VarRange(0, None),
167
167
  repeats_range=VarRange(1, 1),
@@ -202,17 +202,26 @@ class HoloviewResult(PanelResult):
202
202
  ) -> Optional[hv.Curve]:
203
203
  hvds = hv.Dataset(dataset)
204
204
  title = self.title_from_ds(dataset, result_var, **kwargs)
205
-
206
- # print(result_var.name, dataset)
205
+ # print(result_var.name)
206
+ # print( dataset)
207
207
  pt = hv.Overlay()
208
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])
209
+ var = result_var.name
210
+ std_var = f"{var}_std"
211
+
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
+ # for var in dataset.data_vars:
218
+ # print(var)
219
+ # if not var.endswith("_std"):
220
+ # std_var = f"{var}_std"
221
+ # pt *= hvds.to(hv.Curve, vdims=var, label=var).opts(title=title, **kwargs)
222
+ # #Only create a Spread if the matching _std variable exists
223
+ # if std_var in dataset.data_vars:
224
+ # pt *= hvds.to(hv.Spread, vdims=[var, std_var])
216
225
 
217
226
  return pt.opts(legend_position="right")
218
227
 
@@ -0,0 +1,67 @@
1
+ import panel as pn
2
+ from panel.pane import LaTeX
3
+ from typing import Optional, List, Any
4
+
5
+ pn.extension("mathjax")
6
+
7
+
8
+ def latex_text(text: str) -> str:
9
+ """Convert text to LaTeX text format, replacing underscores with spaces."""
10
+ return r"\text{" + text.replace("_", " ") + r"} \\"
11
+
12
+
13
+ def format_values_list(values: List[Any], max_display: int = 5) -> List[Any]:
14
+ """Format a list of values, showing ellipsis if too long."""
15
+ if len(values) <= max_display:
16
+ return values
17
+ return [values[i] for i in [0, 1, 0, -2, -1]]
18
+
19
+
20
+ def create_matrix_array(values: List[Any]) -> str:
21
+ """Create a LaTeX matrix array from values."""
22
+ displayed_vals = format_values_list(values)
23
+ if len(values) > 5:
24
+ displayed_vals[2] = "⋮"
25
+ return r"\\ ".join([str(val) for val in displayed_vals])
26
+
27
+
28
+ def input_var_to_latex(input_var) -> str:
29
+ """Convert input variable to LaTeX format."""
30
+ vals = input_var.values()
31
+ latex_str = r"\begin{array}{c}"
32
+ latex_str += latex_text(input_var.name)
33
+ latex_str += f"{len(vals)}" + r"\times1 \\"
34
+ latex_str += r"\left[ \begin{array}{c}"
35
+ latex_str += create_matrix_array(vals)
36
+ latex_str += r"\end{array} \right] \end{array}"
37
+ return latex_str
38
+
39
+
40
+ def result_var_to_latex(bench_cfg) -> str:
41
+ """Convert result variables to LaTeX format."""
42
+ sizes = [str(len(i.values())) for i in bench_cfg.all_vars]
43
+ if len(sizes) == 1:
44
+ sizes.insert(0, "1")
45
+
46
+ latex_str = r"\begin{array}{c}"
47
+ latex_str += r"\times".join(reversed(sizes)) + r"\\ of \\"
48
+ latex_str += r" \left[\begin{array}{cc}"
49
+ latex_str += "".join(latex_text(rv.name) for rv in bench_cfg.result_vars)
50
+ latex_str += r"\end{array} \right]\end{array}"
51
+ return latex_str
52
+
53
+
54
+ def to_latex(bench_cfg) -> Optional[pn.pane.LaTeX]:
55
+ """Convert benchmark configuration to LaTeX visualization.
56
+
57
+ Returns None if there are no variables to display.
58
+ """
59
+ if not bench_cfg.all_vars:
60
+ return None
61
+
62
+ latex_str = r"\[" + r"\bigtimes".join(input_var_to_latex(iv) for iv in bench_cfg.all_vars)
63
+ latex_str += r"\rightarrow\quad"
64
+ latex_str += result_var_to_latex(bench_cfg)
65
+ latex_str += r"\]"
66
+
67
+ return LaTeX(latex_str.replace("_", r"\;"))
bencher/utils.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from collections import namedtuple
2
2
  import xarray as xr
3
- from sortedcontainers import SortedDict
4
3
  import hashlib
5
4
  import re
6
5
  import math
@@ -27,9 +26,7 @@ def hmap_canonical_input(dic: dict) -> tuple:
27
26
  Returns:
28
27
  tuple: values of the dictionary always in the same order and hashable
29
28
  """
30
-
31
- function_input = SortedDict(dic)
32
- return tuple(function_input.values())
29
+ return tuple(value for _, value in sorted(dic.items()))
33
30
 
34
31
 
35
32
  def make_namedtuple(class_name: str, **fields) -> namedtuple:
bencher/video_writer.py CHANGED
@@ -1,9 +1,8 @@
1
1
  import numpy as np
2
2
  import moviepy.video.io.ImageSequenceClip
3
+ import moviepy.video.io.VideoFileClip
3
4
  from pathlib import Path
4
5
  from .utils import gen_video_path, gen_image_path
5
-
6
- import moviepy
7
6
  from PIL import Image, ImageDraw
8
7
 
9
8
 
@@ -46,6 +45,16 @@ class VideoWriter:
46
45
  new_img.paste(image, (0, padding))
47
46
  return new_img
48
47
 
48
+ @staticmethod
49
+ def convert_to_compatible_format(video_path: str) -> str:
50
+ new_path = Path(video_path)
51
+ new_path = new_path.with_name(f"{new_path.stem}_fixed{new_path.suffix}").as_posix()
52
+ vw = VideoWriter()
53
+ vw.filename = new_path
54
+ with moviepy.video.io.VideoFileClip.VideoFileClip(video_path) as vid:
55
+ vw.write_video_raw(vid)
56
+ return new_path
57
+
49
58
  def write_video_raw(self, video_clip: moviepy.video.VideoClip, fps: int = 30) -> str:
50
59
  video_clip.write_videofile(
51
60
  self.filename,
@@ -59,6 +68,32 @@ class VideoWriter:
59
68
  video_clip.close()
60
69
  return self.filename
61
70
 
71
+ @staticmethod
72
+ def extract_frame(video_path: str, time: float = None, output_path: str = None) -> str:
73
+ """Extract a frame from a video at a specific time.
74
+
75
+ Args:
76
+ video_path: Path to the video file
77
+ time: Time in seconds to extract frame. If None, uses last frame
78
+ output_path: Optional path where to save the image. If None, uses video name with _frame.png
79
+
80
+ Returns:
81
+ str: Path to the saved PNG image
82
+ """
83
+ if output_path is None:
84
+ output_path = (
85
+ Path(video_path).with_stem(f"{Path(video_path).stem}_frame").with_suffix(".png")
86
+ )
87
+ else:
88
+ output_path = Path(output_path)
89
+
90
+ with moviepy.video.io.VideoFileClip.VideoFileClip(video_path) as video:
91
+ frame_time = time if time is not None else video.duration
92
+ frame = video.get_frame(frame_time)
93
+ Image.fromarray(frame).save(output_path)
94
+
95
+ return output_path.as_posix()
96
+
62
97
 
63
98
  def add_image(np_array: np.ndarray, name: str = "img") -> str:
64
99
  """Creates a file on disk from a numpy array and returns the created image path"""
bencher/worker_job.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from typing import List, Tuple, Any
2
2
  from dataclasses import dataclass, field
3
- from sortedcontainers import SortedDict
4
3
  from .utils import hash_sha1
5
4
  from bencher.utils import hmap_canonical_input
6
5
 
@@ -14,7 +13,7 @@ class WorkerJob:
14
13
  bench_cfg_sample_hash: str
15
14
  tag: str
16
15
 
17
- function_input: SortedDict = None
16
+ function_input: dict = None
18
17
  canonical_input: Tuple[Any] = None
19
18
  fn_inputs_sorted: List[str] = None
20
19
  function_input_signature_pure: str = None
@@ -23,7 +22,7 @@ class WorkerJob:
23
22
  msgs: List[str] = field(default_factory=list)
24
23
 
25
24
  def setup_hashes(self) -> None:
26
- self.function_input = SortedDict(zip(self.dims_name, self.function_input_vars))
25
+ self.function_input = dict(zip(self.dims_name, self.function_input_vars))
27
26
 
28
27
  self.canonical_input = hmap_canonical_input(self.function_input)
29
28
 
@@ -32,7 +31,7 @@ class WorkerJob:
32
31
 
33
32
  # store a tuple of the inputs as keys for a holomap
34
33
  # the signature is the hash of the inputs to to the function + meta variables such as repeat and time + the hash of the benchmark sweep as a whole (without the repeats hash)
35
- self.fn_inputs_sorted = list(SortedDict(self.function_input).items())
34
+ self.fn_inputs_sorted = sorted(self.function_input.items())
36
35
  self.function_input_signature_pure = hash_sha1((self.fn_inputs_sorted, self.tag))
37
36
 
38
37
  self.function_input_signature_benchmark_context = hash_sha1(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: holobench
3
- Version: 1.40.0
3
+ Version: 1.41.0
4
4
  Summary: A package for benchmarking the performance of arbitrary functions
5
5
  Project-URL: Repository, https://github.com/dyson-ai/bencher
6
6
  Project-URL: Home, https://github.com/dyson-ai/bencher
@@ -12,28 +12,24 @@ Requires-Python: <3.13,>=3.10
12
12
  Requires-Dist: diskcache<=5.6.3,>=5.6
13
13
  Requires-Dist: holoviews<=1.20.0,>=1.15
14
14
  Requires-Dist: hvplot<=0.10.0,>=0.8
15
- Requires-Dist: matplotlib<=3.10.0,>=3.6.3
16
- Requires-Dist: moviepy-fix-codec
17
- Requires-Dist: numpy<=2.2.2,>=1.0
18
- Requires-Dist: optuna<=4.2.0,>=3.2
15
+ Requires-Dist: moviepy<=2.1.2,>=2.1.2
16
+ Requires-Dist: numpy<=2.2.3,>=1.0
17
+ Requires-Dist: optuna<=4.2.1,>=3.2
19
18
  Requires-Dist: pandas<=2.2.3,>=2.0
20
- Requires-Dist: panel<=1.6.0,>=1.3.6
19
+ Requires-Dist: panel<=1.6.1,>=1.3.6
21
20
  Requires-Dist: param<=2.2.0,>=1.13.0
22
21
  Requires-Dist: plotly<=6.0.0,>=5.15
23
22
  Requires-Dist: scikit-learn<=1.6.1,>=1.2
24
- Requires-Dist: scoop<=0.7.2.0,>=0.7.0
25
- Requires-Dist: sortedcontainers<=2.4,>=2.4
26
- Requires-Dist: str2bool<=1.1,>=1.1
27
23
  Requires-Dist: strenum<=0.4.15,>=0.4.0
28
24
  Requires-Dist: xarray<=2025.1.2,>=2023.7
29
25
  Provides-Extra: rerun
30
26
  Requires-Dist: flask; extra == 'rerun'
31
27
  Requires-Dist: flask-cors; extra == 'rerun'
32
28
  Requires-Dist: rerun-notebook; extra == 'rerun'
33
- Requires-Dist: rerun-sdk==0.21.0; extra == 'rerun'
29
+ Requires-Dist: rerun-sdk==0.22.0; extra == 'rerun'
34
30
  Provides-Extra: test
35
- Requires-Dist: coverage<=7.6.10,>=7.5.4; extra == 'test'
36
- Requires-Dist: hypothesis<=6.124.9,>=6.104.2; extra == 'test'
31
+ Requires-Dist: coverage<=7.6.12,>=7.5.4; extra == 'test'
32
+ Requires-Dist: hypothesis<=6.125.3,>=6.104.2; extra == 'test'
37
33
  Requires-Dist: ipykernel; extra == 'test'
38
34
  Requires-Dist: jupyter-bokeh; extra == 'test'
39
35
  Requires-Dist: nbformat; extra == 'test'
@@ -42,7 +38,7 @@ Requires-Dist: pre-commit<=4.1.0; extra == 'test'
42
38
  Requires-Dist: pylint<=3.3.4,>=3.2.5; extra == 'test'
43
39
  Requires-Dist: pytest-cov<=6.0.0,>=4.1; extra == 'test'
44
40
  Requires-Dist: pytest<=8.3.4,>=7.4; extra == 'test'
45
- Requires-Dist: ruff<=0.9.4,>=0.5.0; extra == 'test'
41
+ Requires-Dist: ruff<=0.9.6,>=0.5.0; extra == 'test'
46
42
  Description-Content-Type: text/markdown
47
43
 
48
44
  # Bencher
@@ -1,24 +1,26 @@
1
+ CHANGELOG.md,sha256=alEi3CoMNOpKigEqP1uvdpuZMkpHJFCfO-tx8a_utss,284
1
2
  bencher/__init__.py,sha256=hWfQxlvuHRsFK4ZPCpRXo3nDzQB52JOUoi67wcnhopE,1890
2
- bencher/bench_cfg.py,sha256=gEpF1J4RAxCQPSkI8npKfhw-o3-8cw80TjiWK7As5WE,18417
3
+ bencher/bench_cfg.py,sha256=FbjRAjbxKyHnb-3gPBLdE4GM_vgJeq7ciySH853j3gI,19040
3
4
  bencher/bench_plot_server.py,sha256=nvGTr981XgWELqV7yID91j6V1UIPGtKilzxHcNWaZ6Q,4196
4
5
  bencher/bench_report.py,sha256=ikMSHceyc8cYFH-sIza167DH-H-_iiTYDm2TmusUHDc,7515
5
6
  bencher/bench_runner.py,sha256=wShmZ504BOKgHj0sOrGZtduyPfJHFFBfHRsz5tYy5_Q,7000
6
7
  bencher/bencher.py,sha256=-vbZIzBr2IYYG7be5Hh8IZgIGUysTxoxQUV6xUToH14,35437
7
- bencher/caching.py,sha256=AusaNrzGGlj5m6zcwcqnTn55Mam2mQdF--oqelO806M,1627
8
+ bencher/caching.py,sha256=RYvh6FLcYlMrfYcbkK5k8ZnT4lP2g5klUgo1oPfXhxg,1565
8
9
  bencher/class_enum.py,sha256=kYHW9qKkKcNdwaXizZL-fTptS_DUEGv4c88yCehk3gc,1492
9
10
  bencher/flask_server.py,sha256=uMhMaySUki5StC-r_TXb4KTVqAiffyqfH7UzQidFqSw,831
10
- bencher/job.py,sha256=8tztOwSYZqULaqD1Xv-wAdA6Rhgsa2I19P-ZzvnWPPw,6218
11
+ bencher/job.py,sha256=cBsyw249iigZi1OhzW_ImU3AZMgCJPgvIDierI9xYNg,6147
11
12
  bencher/optuna_conversions.py,sha256=an-LfPsQXyyvhIZnG8Wl1RQVYMvJj7WOi3YNqoUnuxQ,5356
12
- bencher/utils.py,sha256=DP2GJP28nSEihvZwiV1Rl7YJ5NTrRt2zBLs46eQ37hQ,9887
13
+ bencher/utils.py,sha256=HpNI-CsEFqOgAOO_pYdwqNQzkc6DU1cQeA7x7hTIIvk,9827
13
14
  bencher/utils_rerun.py,sha256=E1itolYJMjmtBE5qcSotiS20I-dobVnjznsTRvZaV0s,1212
14
- bencher/video_writer.py,sha256=z49tAG_ttXc8iWcTkWPJO1QaneaVdsmYL6Hpal-pd4Q,2176
15
- bencher/worker_job.py,sha256=FREi0yWQACFmH86R1j-LH72tALEFkKhLDmmoGQY9Jh4,1571
15
+ bencher/video_writer.py,sha256=7oj_P6n9kWZ9geITSL1atBEdWk-GByRH--wxQJbTgHQ,3613
16
+ bencher/worker_job.py,sha256=F8Zh1yWLaSKtDhkZL0hBZ-I3nc_ifaCOkwWAju3nq4I,1509
16
17
  bencher/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
18
  bencher/example/benchmark_data.py,sha256=DL5Grj7UwnKZz2BHfGNKv35Ln0y2ntFwvZdkchOMHVU,6985
18
19
  bencher/example/example_all.py,sha256=_jOiz07fsjghiIuLfMpZiRVEkPaH7dM8OftOGcdL6cU,1960
19
20
  bencher/example/example_categorical.py,sha256=S6PP3LHZewHVymNZmEY-AEMRlJbv0CEgJ1NRWNDEnC8,3659
20
- bencher/example/example_composable_container.py,sha256=URN_2Wv98_JpjWJUhbvK2YejpqumUJMTbQ9ok07TNZw,3753
21
21
  bencher/example/example_composable_container2.py,sha256=tVcSggLAzuXsiHM00qSJk9fKOgqXbSzzyjs7IayLZCw,5667
22
+ bencher/example/example_composable_container_image.py,sha256=FPk0JUWr8aKRMk5x7CfR2z97a6QNt2BEA_BFgsjwav4,1961
23
+ bencher/example/example_composable_container_video.py,sha256=1kClqIP5ueOBEGSo1NJybmydCYfeyU3GmaqLwvGgfyQ,1849
22
24
  bencher/example/example_consts.py,sha256=upKkrMNYUCS38IA4duuyJHERwdZIMB4FA60Gytu_BzU,1475
23
25
  bencher/example/example_custom_sweep.py,sha256=OvAMqirV9KzbuaQ6ELOAbrRrj5zYHjpEs3tG-rgmFJM,1891
24
26
  bencher/example/example_custom_sweep2.py,sha256=6RBiyVVaxAh5Aul85DfYA5P-lwhwW3Bb54o0CBgTB6Q,1225
@@ -32,8 +34,8 @@ bencher/example/example_floats2D.py,sha256=1V5hCxr0Iz2KT2JyePn-XmugsMXlDzf0GazWW
32
34
  bencher/example/example_holosweep.py,sha256=emNUKCHPb-JrSWPjHajuAlQmUU9A9S7O-jdrvixg0Io,2989
33
35
  bencher/example/example_holosweep_objects.py,sha256=eqOjuTYh4Pis5lGsSeN7BJZXKR2upOSjynEtR0HqyoY,3196
34
36
  bencher/example/example_holosweep_tap.py,sha256=vKGyCdc1H8oECWRACW1kj5s1OJPAUETWHbP88R9hW_A,4475
35
- bencher/example/example_image.py,sha256=9VG2XiQnhksYh6WuU18a4b36KIrF-yY7dhZKdL0oG1I,5490
36
- bencher/example/example_image1.py,sha256=GO-PuiEKcFBma5fVNDi-203ZhYJvP4hojjxsDa9B9HM,2678
37
+ bencher/example/example_image.py,sha256=QovSZtxepBwNSYDjouTCrhtP3NXJUXYoqRT2sFavsio,5554
38
+ bencher/example/example_image1.py,sha256=XAR99ko6f4KZ6pHKoAebF2agTZRm8Hm5DZ1_lHdO2gI,2817
37
39
  bencher/example/example_levels.py,sha256=Gl3hIGYmzLufKWIG_YFTvW-TCfao6Ys6W0uc4dAcizw,6858
38
40
  bencher/example/example_levels2.py,sha256=tMhA6dYYQskzMeAZdaz6jRmQTe-c-jLXfkaUqWT30-I,1117
39
41
  bencher/example/example_pareto.py,sha256=tQxX9g8VfASv2vyRAm-Bv3qsYKjKnU-HyuLXtiZYEpw,2656
@@ -49,11 +51,11 @@ bencher/example/example_simple_float.py,sha256=c3ZR0LXfgGcH63MnUpQovRVnzpx5lpDQs
49
51
  bencher/example/example_simple_float2d.py,sha256=xsVOLO6AtMi9_fybpS_JZnhev5f11YuYWHrAOzJw2dI,1033
50
52
  bencher/example/example_strings.py,sha256=NpOGwC1KRAyAAC2VQZCg09ArraESdU0lupFj4b0I-sQ,1538
51
53
  bencher/example/example_time_event.py,sha256=l2dEut9oYnxxF7kRXnZx8Ohw1EdT5Iezo_b8CwCcCHA,2133
52
- bencher/example/example_video.py,sha256=LUiFV841oQ7r-cP3vSHBT0-fIJ-AK51_HyL2gOLMv9k,3839
54
+ bencher/example/example_video.py,sha256=UGcAoY-DvYRuGQB0UgtVebCFtW2ru0s8MfZbhm3efUk,4527
53
55
  bencher/example/example_workflow.py,sha256=00QnUuViMfX_PqzqkXmg1wPX6yAq7IS7mCL_RFKwrMM,6806
54
56
  bencher/example/experimental/example_bokeh_plotly.py,sha256=3jUKh8eKIAlpklKnp8UopIHhUDw1A0_5CwjeyTzbi7o,846
55
57
  bencher/example/experimental/example_hover_ex.py,sha256=qszw4FkIfqQkVviPSpmUoFOoi6PGotGbsc7Ojyx8EtU,1052
56
- bencher/example/experimental/example_hvplot_explorer.py,sha256=LqTcIHwEj5DPDgvrHw0nKg_JErlraOrWqR0_6hZXvnI,1819
58
+ bencher/example/experimental/example_hvplot_explorer.py,sha256=k3NXqLLDOf_uFi09S0RAkArasTZULMb3upwzqi09hMA,1796
57
59
  bencher/example/experimental/example_interactive.py,sha256=MM1A2EVsKTy95RERTNnld0tUmZmCy8N41_jGm2wlG7U,2619
58
60
  bencher/example/experimental/example_streamnd.py,sha256=LqkTtdY4NhnP5dEB1Ifv7RQ5Vq4dLkp5E3aWnWuzniA,1414
59
61
  bencher/example/experimental/example_streams.py,sha256=rrTmcmxDlirGoyTbJ4LT4fBIAc1k28qjnjy5JxGKyhg,1030
@@ -63,6 +65,7 @@ bencher/example/experimental/example_vector.py,sha256=3o_1dA4dc2HL6uIEvDAcvLPVJB
63
65
  bencher/example/inputs_0D/example_0_in_1_out.py,sha256=Lm4lgNGy6oLAEuqDEWHqWGbU6-T2LUudNtP3NKrFDho,1706
64
66
  bencher/example/inputs_0D/example_0_in_2_out.py,sha256=HFtuuuZspK0Hy_1hEbaQy8Ah3SFtSf04yHbaaB9YYec,1389
65
67
  bencher/example/inputs_1D/example1d_common.py,sha256=QurBf3rYq4B3nG9J7Rra30XXtoE6EeDHjPH0CrQ-T9g,2069
68
+ bencher/example/inputs_1D/example_1_float_2_cat_repeats.py,sha256=E8IfubrWgZLX8yrZ-QdWVmEdzx2x8cjSIQUfcwJRUyk,342
66
69
  bencher/example/inputs_1D/example_1_in_1_out.py,sha256=eqAztAufMNTSVE3xdA9Nyqc8UXUn7Y2cjsIP_T_ITUw,1774
67
70
  bencher/example/inputs_1D/example_1_in_2_out.py,sha256=9qwDF5m25pzwRLeqQB_IO1I0ER07-izc9lFJBcapMdo,1908
68
71
  bencher/example/inputs_1D/example_1_in_2_out_repeats.py,sha256=0xt1B9xkCdDhTa8zBVmV565z22SO0RCQcAkCRuF4c1k,1804
@@ -71,8 +74,8 @@ bencher/example/meta/example_meta.py,sha256=ZXW8LZ1DGs05RiZRHLrOx-qt9x10qL6v2tt7
71
74
  bencher/example/meta/example_meta_cat.py,sha256=j3OCi1Yra47wrXOVr8epMYPGIXjQwdQoCcCICPmE2lo,609
72
75
  bencher/example/meta/example_meta_float.py,sha256=Y-zo7QAZkpt3mQEE4guiPmRHmKjn6-y8D_AjWeGCqEs,598
73
76
  bencher/example/meta/example_meta_levels.py,sha256=ZZ14r99z6cs73ZwvBJvDKdEVIdTyHzrWsenxRgFXfXQ,1410
74
- bencher/example/meta/generate_examples.py,sha256=Uicdr5PlamqiFGgEzEtdPzQPfVRE6UOa1CH-3UQ6T_I,1540
75
- bencher/example/meta/generate_meta.py,sha256=1euRIVEAUlT3a_olmhZXbHMaG9OCSzsgKajXXwf1vOI,3874
77
+ bencher/example/meta/generate_examples.py,sha256=z_EoIRT_g15XftQ3_rHXpt_oAJEy0DBPGh2Vpt-ZVfE,1593
78
+ bencher/example/meta/generate_meta.py,sha256=Pu7bvu5tNKsPuEPFU90g4z1d-ZPEitqhr4rPQe_X_I8,4861
76
79
  bencher/example/optuna/example_optuna.py,sha256=0zA6IIDWe7FM0rnYJ-FHF9GZtrhYdKHQTosUD2Raw0M,2338
77
80
  bencher/example/shelved/example_float2D_scatter.py,sha256=z8ranMq8IcJ1yoVSFDncp3gw-yWG7X9lXLimXKpy5Ks,3372
78
81
  bencher/example/shelved/example_float3D_cone.py,sha256=T3dkiEhjm6z3-Vs2SjCNWPKeHk8Bp4FbANE6yXYc_YM,2970
@@ -81,12 +84,13 @@ bencher/plotting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
81
84
  bencher/plotting/plot_filter.py,sha256=hWRjZa9zTncVJiF6r_DI4Ce1xcU49PxJw4gXk7AzsnA,4931
82
85
  bencher/plotting/plt_cnt_cfg.py,sha256=0P9KjVQSUfPY7Kh7UGAbTqihaTgnmLm3oZ5Nvf-pcjM,3193
83
86
  bencher/results/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
- bencher/results/bench_result.py,sha256=j-Al54h26Qypma0dYbx0hs8lBUUX46xXov7DQAZsG7A,3763
85
- bencher/results/bench_result_base.py,sha256=a_IHbliBtLgziqBjkz0MJiu7JkSkrmz1VzBnLenXF6E,22005
87
+ bencher/results/bench_result.py,sha256=JVVhFVMc4P9FqL6zBKsSK3npOkyn1IEKvNOOkvBciew,3811
88
+ bencher/results/bench_result_base.py,sha256=OgSu--RcpEElJum0y7XIEKyGznSaJvrxxx3ZbhhvIl8,21980
86
89
  bencher/results/dataset_result.py,sha256=qXmFMrVAo_1qM6hhV4XpQqmCz9RiVkQo6ICYmbT-Kvk,8680
87
90
  bencher/results/float_formatter.py,sha256=sX6HNCyaXdHDxC8ybVUHwCJ3qOKbPUkBOplVIHtKWjM,1746
88
- bencher/results/holoview_result.py,sha256=r9G9p2i7r01O2ZnsPoyOJU39ImMQhW1QvGV0mNgolc4,29463
91
+ bencher/results/holoview_result.py,sha256=Nc8m-kdQBylTy0JGB_mES3oaisNzHm8sRjT1mMtWWPo,29821
89
92
  bencher/results/hvplot_result.py,sha256=bYSewYhPLVzW6HF_WPjAhS1ZiRp9FJHs008UEBXgH4Y,1993
93
+ bencher/results/laxtex_result.py,sha256=BL9iNgSoNpE8WTwW_OjVbYdYgRdlP27zv_nQ9PpwLds,2212
90
94
  bencher/results/optuna_result.py,sha256=QtZ4TGRun7gJoFVUjEyXKPF5yakwOSXrqEXQVJdJmm4,13587
91
95
  bencher/results/panel_result.py,sha256=lXOtfhWKSspf53Wgm94DTiVD3rliieHQW96sOdu5UYk,1336
92
96
  bencher/results/plotly_result.py,sha256=wkgfL38qJp6RviekXBYpNPeU4HCf0nbtKDAhu5QZhUg,2132
@@ -96,7 +100,7 @@ bencher/results/composable_container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
96
100
  bencher/results/composable_container/composable_container_base.py,sha256=gmlQl3NQ3LWIfH15neLoZMNos6hbu3SklslfcFDAacA,2778
97
101
  bencher/results/composable_container/composable_container_dataframe.py,sha256=ZbFaQSo4UsRxY8NUdJPjNFW3_kzlm8jtWuoLf8y_t8U,1789
98
102
  bencher/results/composable_container/composable_container_panel.py,sha256=HrOoeGB0y0jGQcxcci_M82ftsvklLkJgo-4SjDBJCks,1232
99
- bencher/results/composable_container/composable_container_video.py,sha256=X6XxBNDglnNLjQ4QrhxJ8W3Re_aLeTZKKVsbjjJ3av8,7107
103
+ bencher/results/composable_container/composable_container_video.py,sha256=yLfGRIswSHHWfFwVFBVz31wzKB9x-3bTfMtr-BqIyzk,8672
100
104
  bencher/variables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
105
  bencher/variables/inputs.py,sha256=B4IycsuZQOx51OGO2e8zK5TjfRWvYXI7Ngle3KpVIdw,6694
102
106
  bencher/variables/parametrised_sweep.py,sha256=fxjKOQ2x5xuCyi0kO1_XS9bXiib1bjThhvpulZPeyv8,7802
@@ -104,7 +108,7 @@ bencher/variables/results.py,sha256=Wq14e8rAj5mcK22325wcaeTMjgZ6JuduqceAHItHFY8,
104
108
  bencher/variables/sweep_base.py,sha256=gfEhKvsb16ZLbe38JewZqu0AMOHpsqwRbZbt-aCg9Bc,6258
105
109
  bencher/variables/time.py,sha256=zcRS5p4ZkFjMta9nZMEuWv86rLnPkUSqyO69QwI5q3E,3142
106
110
  resource/bencher,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
107
- holobench-1.40.0.dist-info/METADATA,sha256=hn3E2quLA2y2qpAyWnuGBOw5lvLG85A_dpUNDc8vO10,6846
108
- holobench-1.40.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
109
- holobench-1.40.0.dist-info/licenses/LICENSE,sha256=dSHXTdRY4Y7qGFMv63UksV700iff7iE-p7GGs6Sbnvo,1065
110
- holobench-1.40.0.dist-info/RECORD,,
111
+ holobench-1.41.0.dist-info/METADATA,sha256=M6tXWaG8Ft_a17Dm8sgcIDuMWEELgI-qmYjcpl5v4FE,6693
112
+ holobench-1.41.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
113
+ holobench-1.41.0.dist-info/licenses/LICENSE,sha256=dSHXTdRY4Y7qGFMv63UksV700iff7iE-p7GGs6Sbnvo,1065
114
+ holobench-1.41.0.dist-info/RECORD,,
@@ -1,106 +0,0 @@
1
- import bencher as bch
2
-
3
- from bencher.example.example_image import BenchPolygons
4
-
5
-
6
- class BenchComposableContainerImage(BenchPolygons):
7
- compose_method = bch.EnumSweep(bch.ComposeType)
8
- labels = bch.BoolSweep()
9
- num_frames = bch.IntSweep(default=5, bounds=[1, 100])
10
- polygon_vid = bch.ResultVideo()
11
-
12
- def __call__(self, **kwargs):
13
- self.update_params_from_kwargs(**kwargs)
14
- var_name = None
15
- var_value = None
16
-
17
- if self.labels:
18
- var_name = "sides"
19
- var_value = self.sides
20
- vr = bch.ComposableContainerVideo()
21
- for i in range(self.num_frames):
22
- res = super().__call__(start_angle=i)
23
- print(res)
24
- vr.append(res["polygon"])
25
- self.polygon_vid = vr.to_video(
26
- bch.RenderCfg(
27
- compose_method=self.compose_method,
28
- var_name=var_name,
29
- var_value=var_value,
30
- max_frame_duration=1.0 / 20.0,
31
- )
32
- )
33
- return self.get_results_values_as_dict()
34
-
35
-
36
- class BenchComposableContainerVideo(bch.ParametrizedSweep):
37
- unequal_length = bch.BoolSweep()
38
- compose_method = bch.EnumSweep(bch.ComposeType)
39
- labels = bch.BoolSweep()
40
- polygon_vid = bch.ResultVideo()
41
-
42
- def __call__(self, **kwargs):
43
- self.update_params_from_kwargs(**kwargs)
44
- vr = bch.ComposableContainerVideo()
45
- for i in range(3, 5):
46
- num_frames = i * 10 if self.unequal_length else 5
47
- res = BenchComposableContainerImage().__call__(
48
- compose_method=bch.ComposeType.sequence, sides=i, num_frames=num_frames
49
- )
50
- vr.append(res["polygon_vid"])
51
-
52
- self.polygon_vid = vr.to_video(bch.RenderCfg(compose_method=kwargs.get("compose_method")))
53
- return self.get_results_values_as_dict()
54
-
55
-
56
- def example_composable_container_image(
57
- run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
58
- ) -> bch.Bench:
59
- bench = BenchComposableContainerImage().to_bench(run_cfg, report)
60
- bench.result_vars = ["polygon_vid"]
61
- # bench.add_plot_callback(bch.BenchResult.to_panes)
62
- # bench.add_plot_callback(bch.BenchResult.to_video_grid, result_types=(bch.ResultVideo))
63
- # bench.add_plot_callback(bch.BenchResult.to_video_summary, result_types=(bch.ResultVideo))
64
- # bench.plot_sweep(input_vars=["compose_method", "labels"])
65
-
66
- bench.plot_sweep(input_vars=["compose_method"])
67
-
68
- # bench.compose_
69
- # bench.plot_sweep(
70
- # input_vars=[bch.p("num_frames", [2, 8, 20])],
71
- # const_vars=dict(compose_method=bch.ComposeType.sequence),
72
- # )
73
-
74
- return bench
75
-
76
-
77
- def example_composable_container_video(
78
- run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
79
- ) -> bch.Bench:
80
- bench = BenchComposableContainerVideo().to_bench(run_cfg, report)
81
-
82
- bench.result_vars = ["polygon_vid"]
83
- bench.add_plot_callback(bch.BenchResult.to_panes)
84
- bench.add_plot_callback(bch.BenchResult.to_video_grid, result_types=(bch.ResultVideo))
85
- bench.add_plot_callback(bch.BenchResult.to_video_summary, result_types=(bch.ResultVideo))
86
- bench.plot_sweep(input_vars=["compose_method", "labels"], const_vars=dict(unequal_length=True))
87
-
88
- res = bench.plot_sweep(
89
- input_vars=[],
90
- const_vars=dict(unequal_length=False, compose_method=bch.ComposeType.sequence),
91
- plot_callbacks=False,
92
- )
93
-
94
- bench.report.append(res.to_video_grid())
95
-
96
- return bench
97
-
98
-
99
- if __name__ == "__main__":
100
- ex_run_cfg = bch.BenchRunCfg()
101
- ex_run_cfg.cache_samples = False
102
- # ex_run_cfg.level = 2
103
- ex_report = bch.BenchReport()
104
- example_composable_container_image(ex_run_cfg, report=ex_report)
105
- # example_composable_container_video(ex_run_cfg, report=ex_report)
106
- ex_report.show()