Skip to content

Commit

Permalink
Merge pull request #416 from dyson-ai/composable/container_dateframe
Browse files Browse the repository at this point in the history
Composable/container dateframe
  • Loading branch information
blooop authored Jul 1, 2024
2 parents d5bb88e + 65c88a2 commit 8724a1c
Show file tree
Hide file tree
Showing 17 changed files with 576 additions and 71 deletions.
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@
# numpy file format
*.npy filter=lfs diff=lfs merge=lfs -text
# GitHub syntax highlighting
pixi.lock linguist-language=YAML merge=ours
pixi.lock linguist-language=YAML merge=ours
1 change: 1 addition & 0 deletions bencher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
ResultReference,
ResultVolume,
OptDir,
ResultDataSet,
curve,
)

Expand Down
14 changes: 13 additions & 1 deletion bencher/bencher.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
ResultString,
ResultContainer,
ResultReference,
ResultDataSet,
)
from bencher.results.bench_result import BenchResult
from bencher.variables.parametrised_sweep import ParametrizedSweep
Expand Down Expand Up @@ -612,19 +613,21 @@ def setup_dataset(
)
# xarray stores K N-dimensional arrays of data. Each array is named and in this case we have a nd array for each result variable
data_vars = {}
dataset_list = []

for rv in bench_cfg.result_vars:
if isinstance(rv, ResultVar):
result_data = np.full(dims_cfg.dims_size, np.nan, dtype=float)
data_vars[rv.name] = (dims_cfg.dims_name, result_data)
if isinstance(rv, ResultReference):
if isinstance(rv, (ResultReference, ResultDataSet)):
result_data = np.full(dims_cfg.dims_size, -1, dtype=int)
data_vars[rv.name] = (dims_cfg.dims_name, result_data)
if isinstance(
rv, (ResultPath, ResultVideo, ResultImage, ResultString, ResultContainer)
):
result_data = np.full(dims_cfg.dims_size, "NAN", dtype=object)
data_vars[rv.name] = (dims_cfg.dims_name, result_data)

elif type(rv) == ResultVec:
for i in range(rv.size):
result_data = np.full(dims_cfg.dims_size, np.nan)
Expand All @@ -633,6 +636,7 @@ def setup_dataset(
bench_res = BenchResult(bench_cfg)
bench_res.ds = xr.Dataset(data_vars=data_vars, coords=dims_cfg.coords)
bench_res.ds_dynamic = self.ds_dynamic
bench_res.dataset_list = dataset_list
bench_res.setup_object_index()

return bench_res, function_inputs, dims_cfg.dims_name
Expand Down Expand Up @@ -770,13 +774,21 @@ def store_results(
),
):
set_xarray_multidim(bench_res.ds[rv.name], worker_job.index_tuple, result_value)
elif isinstance(rv, ResultDataSet):
bench_res.dataset_list.append(result_value)
set_xarray_multidim(
bench_res.ds[rv.name],
worker_job.index_tuple,
len(bench_res.dataset_list) - 1,
)
elif isinstance(rv, ResultReference):
bench_res.object_index.append(result_value)
set_xarray_multidim(
bench_res.ds[rv.name],
worker_job.index_tuple,
len(bench_res.object_index) - 1,
)

elif isinstance(rv, ResultVec):
if isinstance(result_value, (list, np.ndarray)):
if len(result_value) == rv.size:
Expand Down
48 changes: 48 additions & 0 deletions bencher/example/example_dataframe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import bencher as bch

import xarray as xr
import numpy as np
import holoviews as hv


class ExampleMergeDataset(bch.ParametrizedSweep):

value = bch.FloatSweep(default=0, bounds=[0, 10])
repeats_x = bch.IntSweep(default=2, bounds=[2, 4])
# repeats_y = bch.IntSweep(default=2, bounds=[2, 4])

result_df = bch.ResultDataSet()

def __call__(self, **kwargs):
self.update_params_from_kwargs(**kwargs)
# First, create a DataArray from the vector
vector = [v + self.value for v in range(1, self.repeats_x)]
data_array = xr.DataArray(vector, dims=["index"], coords={"index": np.arange(len(vector))})
# Convert the DataArray to a Dataset
result_df = xr.Dataset({"result_df": data_array})
self.result_df = bch.ResultDataSet(result_df.to_pandas())
return super().__call__(**kwargs)


def example_dataset(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None):
bench = ExampleMergeDataset().to_bench(run_cfg, report)
res = bench.plot_sweep(input_vars=["value"], const_vars=dict(repeats_x=4))
# bench.report.append(res.to_panes(target_dimension=1))
# bench.report.append(res.to_panes(target_dimension=2))
# bench.reprt.append(res.to_video_grid
# # bch.BenchResult.to_video_grid,
# target_duration=0.06,
# compose_method_list=[
# bch.ComposeType.right,
# bch.ComposeType.right,
# bch.ComposeType.sequence,
# ],
# )
# bench.report.append(res.to_panes(container=hv.Bars,target_dimension=1))
# bench.report.append(res.to_panes(container=hv.Curve))
bench.report.append(res.to_dataset1(container=hv.Curve))
return bench


if __name__ == "__main__":
example_dataset().report.show()
12 changes: 5 additions & 7 deletions bencher/example/example_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,12 @@ def simple():

# res = bench.sweep(input_vars=["sides", "radius"])

# bench.report.append(res.to_heatmap(target_dimension=3))

bench.plot_sweep(input_vars=["sides"])
bench.plot_sweep(input_vars=["sides", "color"])

bench.plot_sweep(input_vars=["sides", "radius"])

# bench.report.append(res.to_line(target_dimension=1))
res = bench.plot_sweep(input_vars=["sides", "radius"])
bench.report.append(res.to_heatmap(target_dimension=3))
bench.report.append(res.to_line(target_dimension=1))

return bench

Expand All @@ -148,8 +146,8 @@ def example_image_vid_sequential(
# ex_run_cfg.debug = True
# ex_run_cfg.repeats = 2
ex_run_cfg.level = 4
example_image_vid(ex_run_cfg).report.show()
# simple().report.show()
# example_image_vid(ex_run_cfg).report.show()
simple().report.show()

# example_image_vid_sequential(ex_run_cfg).report.show()
# example_image(ex_run_cfg).report.show()
81 changes: 81 additions & 0 deletions bencher/example/example_image1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import bencher as bch
import numpy as np
import math
import matplotlib.pyplot as plt


def polygon_points(radius: float, sides: int, start_angle: float):
points = []
for ang in np.linspace(0, 360, sides + 1):
angle = math.radians(start_angle + ang)
points.append(([math.sin(angle) * radius, math.cos(angle) * radius]))
return points


class BenchPolygons(bch.ParametrizedSweep):
sides = bch.IntSweep(default=3, bounds=(3, 7))
radius = bch.FloatSweep(default=1, bounds=(0.2, 1))
linewidth = bch.FloatSweep(default=1, bounds=(1, 10))
linestyle = bch.StringSweep(["solid", "dashed", "dotted"])
color = bch.StringSweep(["red", "green", "blue"])
start_angle = bch.FloatSweep(default=0, bounds=[0, 360])
polygon = bch.ResultImage()
polygon_small = bch.ResultImage()

area = bch.ResultVar()
side_length = bch.ResultVar()

def __call__(self, **kwargs):
self.update_params_from_kwargs(**kwargs)
points = polygon_points(self.radius, self.sides, self.start_angle)
# self.hmap = hv.Curve(points)
self.polygon = self.points_to_polygon_png(points, bch.gen_image_path("polygon"), dpi=30)
self.polygon_small = self.points_to_polygon_png(
points, bch.gen_image_path("polygon"), dpi=10
)

self.side_length = 2 * self.radius * math.sin(math.pi / self.sides)
self.area = (self.sides * self.side_length**2) / (4 * math.tan(math.pi / self.sides))
return super().__call__()

def points_to_polygon_png(self, points: list[float], filename: str, dpi):
"""Draw a closed polygon and save to png"""
fig = plt.figure(frameon=False)
ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0], frameon=False)
ax.set_axis_off()
ax.plot(
[p[0] for p in points],
[p[1] for p in points],
linewidth=self.linewidth,
linestyle=self.linestyle,
color=self.color,
)
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)

ax.set_aspect("equal")
fig.add_axes(ax)
fig.savefig(filename, dpi=dpi)

return filename


def example_image_vid_sequential1(
run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
) -> bch.Bench:
bench = BenchPolygons().to_bench(run_cfg, report)
res = bench.plot_sweep(input_vars=["sides"])

bench.report.append(res.to_panes(zip_results=True))

return bench


if __name__ == "__main__":

ex_run_cfg = bch.BenchRunCfg()
ex_run_cfg.use_sample_cache = True
ex_run_cfg.overwrite_sample_cache = True
ex_run_cfg.level = 3

example_image_vid_sequential1(ex_run_cfg).report.show()
4 changes: 3 additions & 1 deletion bencher/results/bench_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@
from bencher.results.panel_result import PanelResult
from bencher.results.plotly_result import PlotlyResult
from bencher.results.holoview_result import HoloviewResult
from bencher.results.dataset_result import DataSetResult
from bencher.utils import listify


class BenchResult(PlotlyResult, HoloviewResult, VideoSummaryResult):
class BenchResult(PlotlyResult, HoloviewResult, VideoSummaryResult, DataSetResult):
"""Contains the results of the benchmark and has methods to cast the results to various datatypes and graphical representations"""

def __init__(self, bench_cfg) -> None:
PlotlyResult.__init__(self, bench_cfg)
HoloviewResult.__init__(self, bench_cfg)
# DataSetResult.__init__(self.bench_cfg)

@staticmethod
def default_plot_callbacks():
Expand Down
57 changes: 53 additions & 4 deletions bencher/results/bench_result_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
from bencher.plotting.plot_filter import VarRange, PlotFilter
from bencher.utils import listify

from bencher.variables.results import (
ResultReference,
)
from bencher.variables.results import ResultReference, ResultDataSet

from bencher.results.composable_container.composable_container_panel import ComposableContainerPanel

Expand Down Expand Up @@ -242,6 +240,46 @@ def map_plots(
row.append(plot_callback(rv))
return row.get()

@staticmethod
def zip_results1D(args): # pragma: no cover
first_el = [a[0] for a in args]
out = pn.Column()
for a in zip(*first_el):
row = pn.Row()
row.append(a[0])
for a1 in range(1, len(a[1])):
row.append(a[a1][1])
out.append(row)
return out

@staticmethod
def zip_results1D1(panel_list): # pragma: no cover
container_args = {"styles": {}}
container_args["styles"]["border-bottom"] = f"{2}px solid grey"
print(panel_list)
out = pn.Column()
for a in zip(*panel_list):
row = pn.Row(**container_args)
row.append(a[0][0])
for a1 in range(0, len(a)):
row.append(a[a1][1])
out.append(row)
return out

@staticmethod
def zip_results1D2(panel_list): # pragma: no cover
if panel_list is not None:
print(panel_list)
primary = panel_list[0]
secondary = panel_list[1:]
for i in range(len(primary)):
print(type(primary[i]))
if isinstance(primary[i], (pn.Column, pn.Row)):
for j in range(len(secondary)):
primary[i].append(secondary[j][i][1])
return primary
return panel_list

def map_plot_panes(
self,
plot_callback: callable,
Expand All @@ -250,6 +288,7 @@ def map_plot_panes(
result_var: ResultVar = None,
result_types=None,
pane_collection: pn.pane = None,
zip_results=False,
**kwargs,
) -> Optional[pn.Row]:
if hv_dataset is None:
Expand All @@ -271,6 +310,9 @@ def map_plot_panes(
target_dimension=target_dimension,
)
)

if zip_results:
return self.zip_results1D2(row.get())
return row.get()

def filter(
Expand Down Expand Up @@ -405,10 +447,17 @@ def zero_dim_da_to_val(self, da_ds: xr.DataArray | xr.Dataset) -> Any:
return da_ds.values.squeeze().item()
return da.expand_dims(dim).values[0]

def ds_to_container(
def ds_to_container( # pylint: disable=too-many-return-statements
self, dataset: xr.Dataset, result_var: Parameter, container, **kwargs
) -> Any:
val = self.zero_dim_da_to_val(dataset[result_var.name])
if isinstance(result_var, ResultDataSet):
ref = self.dataset_list[val]
if ref is not None:
if container is not None:
return container(ref.obj)
return ref.obj
return None
if isinstance(result_var, ResultReference):
ref = self.object_index[val]
if ref is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ComposeType(StrEnum):
right = auto() # append the container to the right (creates a row)
down = auto() # append the container below (creates a column)
sequence = auto() # display the container after (in time)
# overlay = auto() # overlay on top of the current container (alpha blending)
overlay = auto() # overlay on top of the current container (alpha blending)

def flip(self):
match self:
Expand Down
Loading

0 comments on commit 8724a1c

Please sign in to comment.