potassco-benchmark-tool 2.1.1__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.
- benchmarktool/__init__.py +0 -0
- benchmarktool/entry_points.py +417 -0
- benchmarktool/init/programs/gcat.sh +24 -0
- benchmarktool/init/runscripts/runscript-all.xml +49 -0
- benchmarktool/init/runscripts/runscript-dist.xml +20 -0
- benchmarktool/init/runscripts/runscript-example.xml +31 -0
- benchmarktool/init/runscripts/runscript-seq.xml +27 -0
- benchmarktool/init/templates/seq-generic-single.sh +27 -0
- benchmarktool/init/templates/seq-generic-zip.sh +14 -0
- benchmarktool/init/templates/seq-generic.sh +12 -0
- benchmarktool/init/templates/single.dist +25 -0
- benchmarktool/result/__init__.py +0 -0
- benchmarktool/result/ipynb_gen.py +477 -0
- benchmarktool/result/ods_config.py +42 -0
- benchmarktool/result/ods_gen.py +714 -0
- benchmarktool/result/parser.py +167 -0
- benchmarktool/result/result.py +453 -0
- benchmarktool/resultparser/__init__.py +0 -0
- benchmarktool/resultparser/clasp.py +88 -0
- benchmarktool/runscript/__init__.py +0 -0
- benchmarktool/runscript/parser.py +477 -0
- benchmarktool/runscript/runscript.py +1481 -0
- benchmarktool/tools.py +82 -0
- potassco_benchmark_tool-2.1.1.dist-info/METADATA +112 -0
- potassco_benchmark_tool-2.1.1.dist-info/RECORD +29 -0
- potassco_benchmark_tool-2.1.1.dist-info/WHEEL +5 -0
- potassco_benchmark_tool-2.1.1.dist-info/entry_points.txt +2 -0
- potassco_benchmark_tool-2.1.1.dist-info/licenses/LICENSE +21 -0
- potassco_benchmark_tool-2.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generate jupyter notebook for result visualization
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import nbformat as nbf
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# mypy: disable-error-code="no-untyped-call"
|
|
9
|
+
def gen_ipynb(parquet_file: str, file_name: str) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Generate jupyter notebook for result visualization.
|
|
12
|
+
|
|
13
|
+
Attributes
|
|
14
|
+
parquet_file (str): Name of the parquet file containing the data.
|
|
15
|
+
file_name (str): Name of the Jupyter notebook file.
|
|
16
|
+
"""
|
|
17
|
+
intro = """\
|
|
18
|
+
# Visualization of results
|
|
19
|
+
|
|
20
|
+
You can install all required packages for this notebook by using the following command
|
|
21
|
+
inside the benchmark-tool directory.
|
|
22
|
+
```bash
|
|
23
|
+
$ pip install .[plot]
|
|
24
|
+
```
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
data_heading = """\
|
|
28
|
+
### Obtain data
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
data_code = f'''\
|
|
32
|
+
from typing import Any
|
|
33
|
+
|
|
34
|
+
import ipywidgets as widgets
|
|
35
|
+
import numpy as np
|
|
36
|
+
import pandas as pd
|
|
37
|
+
import plotly.express as px
|
|
38
|
+
import plotly.graph_objects as go
|
|
39
|
+
from ipywidgets.widgets.interaction import fixed
|
|
40
|
+
|
|
41
|
+
df_in = pd.read_parquet("{parquet_file}")
|
|
42
|
+
|
|
43
|
+
settings: set[str] = set()
|
|
44
|
+
measures: set[str] = set()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_metadata(df: pd.DataFrame) -> dict[str, Any]:
|
|
48
|
+
"""
|
|
49
|
+
Extract metadata from dataframe.
|
|
50
|
+
|
|
51
|
+
Attributes
|
|
52
|
+
df (pd.DataFrame): DataFrame.
|
|
53
|
+
"""
|
|
54
|
+
meta: dict[str, Any] = {{}}
|
|
55
|
+
for col in df.columns:
|
|
56
|
+
if col[0] == "_metadata":
|
|
57
|
+
meta[col[1]] = list(df.loc[df[col[0]][col[1]] != "nan", (col[0], col[1])])
|
|
58
|
+
elif col[0] != "":
|
|
59
|
+
measures.add(col[0])
|
|
60
|
+
settings.add(col[1])
|
|
61
|
+
df.drop("_metadata", axis=1, level=0, inplace=True)
|
|
62
|
+
return meta
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
metadata = get_metadata(df_in)
|
|
66
|
+
|
|
67
|
+
df_fill = (
|
|
68
|
+
df_in.loc[: int(float(metadata["offset"][0])), [("", "instance")]]
|
|
69
|
+
.replace("<NA>", np.nan)
|
|
70
|
+
.ffill()
|
|
71
|
+
.combine_first(df_in.drop(columns=("", "instance")))
|
|
72
|
+
.loc[: int(float(metadata["offset"][0])),]
|
|
73
|
+
)
|
|
74
|
+
'''
|
|
75
|
+
|
|
76
|
+
funcs_heading = """\
|
|
77
|
+
### Helper functions
|
|
78
|
+
"""
|
|
79
|
+
funcs_code = '''\
|
|
80
|
+
def multi_checkbox_widget(options_dict: dict[str, widgets.Checkbox]) -> widgets.VBox:
|
|
81
|
+
"""
|
|
82
|
+
Widget with a search field and lots of checkboxes.
|
|
83
|
+
Based on 'https://gist.github.com/MattJBritton/9dc26109acb4dfe17820cf72d82f1e6f'.
|
|
84
|
+
|
|
85
|
+
Attributes:
|
|
86
|
+
options_dict (dict): Widget options.
|
|
87
|
+
"""
|
|
88
|
+
search_widget = widgets.Text()
|
|
89
|
+
output_widget = widgets.Output()
|
|
90
|
+
options = list(options_dict.values())
|
|
91
|
+
options_layout = widgets.Layout(
|
|
92
|
+
overflow="auto", border="1px solid black", width="300px", height="300px", flex_flow="column", display="flex"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# selected_widget = wid.Box(children=[options[0]])
|
|
96
|
+
options_widget = widgets.VBox(options, layout=options_layout)
|
|
97
|
+
# left_widget = wid.VBox(search_widget, selected_widget)
|
|
98
|
+
multi_select = widgets.VBox([search_widget, options_widget])
|
|
99
|
+
|
|
100
|
+
@output_widget.capture()
|
|
101
|
+
def on_checkbox_change(change):
|
|
102
|
+
"""
|
|
103
|
+
Helper function to sort checkboxes based on selection.
|
|
104
|
+
"""
|
|
105
|
+
# change["owner"].description
|
|
106
|
+
# print(options_widget.children)
|
|
107
|
+
# selected_item = wid.Button(description = change["new"])
|
|
108
|
+
# selected_widget.children = [] #selected_widget.children + [selected_item]
|
|
109
|
+
options_widget.children = sorted(list(options_widget.children), key=lambda x: x.value, reverse=True)
|
|
110
|
+
|
|
111
|
+
for checkbox in options:
|
|
112
|
+
checkbox.observe(on_checkbox_change, names="value")
|
|
113
|
+
|
|
114
|
+
@output_widget.capture()
|
|
115
|
+
def on_text_change(change):
|
|
116
|
+
"""
|
|
117
|
+
Helper function to filter checkboxes based on search field.
|
|
118
|
+
"""
|
|
119
|
+
search_input = change["new"]
|
|
120
|
+
if search_input == "":
|
|
121
|
+
# Reset search field
|
|
122
|
+
new_options = sorted(options, key=lambda x: x.value, reverse=True)
|
|
123
|
+
else:
|
|
124
|
+
# Filter by search field using difflib.
|
|
125
|
+
# close_matches = difflib.get_close_matches(search_input, list(options_dict.keys()), cutoff=0.0)
|
|
126
|
+
close_matches = [x for x in list(options_dict.keys()) if str.lower(search_input.strip("")) in str.lower(x)]
|
|
127
|
+
new_options = sorted(
|
|
128
|
+
[x for x in options if x.description in close_matches], key=lambda x: x.value, reverse=True
|
|
129
|
+
) # [options_dict[x] for x in close_matches]
|
|
130
|
+
options_widget.children = new_options
|
|
131
|
+
|
|
132
|
+
search_widget.observe(on_text_change, names="value")
|
|
133
|
+
display(output_widget)
|
|
134
|
+
return multi_select
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def prepare_data(data: pd.DataFrame, measure: str, merge: str) -> pd.DataFrame:
|
|
138
|
+
"""
|
|
139
|
+
Prepare data for plotting.
|
|
140
|
+
|
|
141
|
+
Attributes:
|
|
142
|
+
data_frame (pd.DataFrame): Input data.
|
|
143
|
+
measure (str): Measure to plot.
|
|
144
|
+
merge (str): How to merge runs (none, mean, median).
|
|
145
|
+
"""
|
|
146
|
+
cs = list(data[measure].columns)
|
|
147
|
+
df_plot = pd.DataFrame()
|
|
148
|
+
df_plot["instance"] = data.loc[:, ("", "instance")]
|
|
149
|
+
for c in cs:
|
|
150
|
+
df_plot[c] = pd.to_numeric(data.loc[:, (measure, c)], errors="coerce")
|
|
151
|
+
|
|
152
|
+
if merge == "median":
|
|
153
|
+
df_plot = df_plot.groupby(
|
|
154
|
+
"instance", dropna=False).median().reset_index()
|
|
155
|
+
elif merge == "mean":
|
|
156
|
+
df_plot = df_plot.groupby(
|
|
157
|
+
"instance", dropna=False).mean().reset_index()
|
|
158
|
+
|
|
159
|
+
df_plot = df_plot.drop(["instance"], axis=1)
|
|
160
|
+
df_plot.loc[-1] = [0 for x in range(len(df_plot.columns))]
|
|
161
|
+
df_plot.sort_index(inplace=True)
|
|
162
|
+
df_plot.index = df_plot.index + 1
|
|
163
|
+
|
|
164
|
+
res = pd.DataFrame()
|
|
165
|
+
for c in cs:
|
|
166
|
+
s = df_plot[c].sort_values(ignore_index=True).drop_duplicates(keep="last")
|
|
167
|
+
key = "_to_" + c
|
|
168
|
+
if key in metadata:
|
|
169
|
+
tl = max(map(float, metadata[key]))
|
|
170
|
+
s.mask(s.ge(tl), inplace=True)
|
|
171
|
+
res = pd.concat([res, s], axis=1)
|
|
172
|
+
return res.sort_index()
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def prepare_plots(
|
|
176
|
+
data: pd.DataFrame, measure: str, merge: str, mode: str, width: int, height: int
|
|
177
|
+
) -> tuple[go.FigureWidget, dict[str, int]]:
|
|
178
|
+
"""
|
|
179
|
+
Prepare plotly figure and traces.
|
|
180
|
+
Attributes:
|
|
181
|
+
data (pd.DataFrame): Input data.
|
|
182
|
+
measure (str): Measure to plot.
|
|
183
|
+
merge (str): How to merge runs (none, mean, median).
|
|
184
|
+
mode (str): Plot mode (cactus, cdf).
|
|
185
|
+
width (int): Plot width.
|
|
186
|
+
height (int): Plot height.
|
|
187
|
+
"""
|
|
188
|
+
plot_data = prepare_data(data, measure, merge)
|
|
189
|
+
|
|
190
|
+
fig = go.Figure()
|
|
191
|
+
colors = px.colors.qualitative.G10
|
|
192
|
+
switch_xy = False
|
|
193
|
+
|
|
194
|
+
# set up multiple traces
|
|
195
|
+
i = 0
|
|
196
|
+
lookup = {}
|
|
197
|
+
for col in plot_data.columns:
|
|
198
|
+
val = plot_data[[col]].dropna()
|
|
199
|
+
if mode == "Survivor":
|
|
200
|
+
x_vals = val[col].cumsum()
|
|
201
|
+
y_vals = val.index
|
|
202
|
+
switch_xy = False
|
|
203
|
+
elif mode == "Cactus":
|
|
204
|
+
x_vals = val.index
|
|
205
|
+
y_vals = val[col]
|
|
206
|
+
switch_xy = True
|
|
207
|
+
else:
|
|
208
|
+
x_vals = val[col]
|
|
209
|
+
y_vals = val.index
|
|
210
|
+
switch_xy = False
|
|
211
|
+
fig.add_trace(
|
|
212
|
+
go.Scatter(
|
|
213
|
+
x=x_vals,
|
|
214
|
+
y=y_vals,
|
|
215
|
+
name=col,
|
|
216
|
+
visible=False,
|
|
217
|
+
line={"shape": "hv"},
|
|
218
|
+
marker=dict(color=colors[i % len(colors)], size=15),
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
lookup[col] = i
|
|
222
|
+
i += 1
|
|
223
|
+
|
|
224
|
+
if switch_xy:
|
|
225
|
+
fig.update_layout(
|
|
226
|
+
xaxis={"title": {"text": "# of instances"}},
|
|
227
|
+
yaxis={"title": {"text": "Time in s"}},
|
|
228
|
+
updatemenus=[
|
|
229
|
+
{
|
|
230
|
+
"buttons": [
|
|
231
|
+
{"label": "Linear", "method": "relayout", "args": [{"yaxis.type": "linear"}]},
|
|
232
|
+
{"label": "Log", "method": "relayout", "args": [{"yaxis.type": "log"}]},
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
],
|
|
236
|
+
)
|
|
237
|
+
else:
|
|
238
|
+
fig.update_layout(
|
|
239
|
+
xaxis={"title": {"text": "Time in s"}},
|
|
240
|
+
yaxis={"title": {"text": "# of instances"}},
|
|
241
|
+
updatemenus=[
|
|
242
|
+
{
|
|
243
|
+
"buttons": [
|
|
244
|
+
{"label": "Linear", "method": "relayout", "args": [{"xaxis.type": "linear"}]},
|
|
245
|
+
{"label": "Log", "method": "relayout", "args": [{"xaxis.type": "log"}]},
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
fig.update_layout(
|
|
252
|
+
title={"text": f"{mode} plot"},
|
|
253
|
+
autosize=False,
|
|
254
|
+
width=width,
|
|
255
|
+
height=height,
|
|
256
|
+
# font=dict(
|
|
257
|
+
# family="Courier New, monospace",
|
|
258
|
+
# size=18,
|
|
259
|
+
# color="RebeccaPurple"
|
|
260
|
+
# ),
|
|
261
|
+
legend={
|
|
262
|
+
"orientation": "h",
|
|
263
|
+
"yanchor": "bottom",
|
|
264
|
+
"y": -0.4 * 500 / height,
|
|
265
|
+
"xanchor": "center",
|
|
266
|
+
"x": 0.5,
|
|
267
|
+
"maxheight": 0.1,
|
|
268
|
+
"title_text": "Setting",
|
|
269
|
+
},
|
|
270
|
+
margin={
|
|
271
|
+
"l": 50,
|
|
272
|
+
"r": 50,
|
|
273
|
+
"b": 50,
|
|
274
|
+
"t": 50,
|
|
275
|
+
"pad": 10,
|
|
276
|
+
},
|
|
277
|
+
)
|
|
278
|
+
fig.update_yaxes(automargin=True)
|
|
279
|
+
fig.update_xaxes(automargin=True)
|
|
280
|
+
return go.FigureWidget(fig), lookup
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def plot(
|
|
284
|
+
data: pd.DataFrame,
|
|
285
|
+
measure: str,
|
|
286
|
+
merge: str,
|
|
287
|
+
mode: str,
|
|
288
|
+
width: int,
|
|
289
|
+
height: int,
|
|
290
|
+
opts: dict[str, Any],
|
|
291
|
+
sets: dict[str, list[str]],
|
|
292
|
+
) -> None:
|
|
293
|
+
"""
|
|
294
|
+
Prepare plot and traces.
|
|
295
|
+
Attributes:
|
|
296
|
+
data (pd.DataFrame): Input data.
|
|
297
|
+
measure (str): Measure to plot
|
|
298
|
+
merge (str): How to merge runs (mean, median).
|
|
299
|
+
mode (str): Plot mode (cactus, cdf).
|
|
300
|
+
width (int): Plot width.
|
|
301
|
+
height (int): Plot height.
|
|
302
|
+
opts (dict): Widget options.
|
|
303
|
+
sets (dict): System:Settings association
|
|
304
|
+
"""
|
|
305
|
+
|
|
306
|
+
def f(**args: Any) -> None:
|
|
307
|
+
"""
|
|
308
|
+
Update trace visibility based on selected options.
|
|
309
|
+
Attributes:
|
|
310
|
+
args: Should contain selected settings, figure widget, lookup table, and sets.
|
|
311
|
+
"""
|
|
312
|
+
figure_widget = args.pop("fig")
|
|
313
|
+
lookup = args.pop("lookup")
|
|
314
|
+
sets = args.pop("sets")
|
|
315
|
+
s = sorted([key for key, value in args.items() if value])
|
|
316
|
+
select = []
|
|
317
|
+
for ss in s:
|
|
318
|
+
if ss in sets:
|
|
319
|
+
select += sets[ss]
|
|
320
|
+
else:
|
|
321
|
+
select.append(ss)
|
|
322
|
+
|
|
323
|
+
for col, i in lookup.items():
|
|
324
|
+
if col in select:
|
|
325
|
+
figure_widget.data[i].visible = True
|
|
326
|
+
else:
|
|
327
|
+
figure_widget.data[i].visible = False
|
|
328
|
+
|
|
329
|
+
display(figure_widget)
|
|
330
|
+
|
|
331
|
+
fig, lookup = prepare_plots(data, measure, merge, mode, width, height)
|
|
332
|
+
opts["fig"] = fixed(fig)
|
|
333
|
+
opts["lookup"] = fixed(lookup)
|
|
334
|
+
opts["sets"] = fixed(sets)
|
|
335
|
+
|
|
336
|
+
out = widgets.interactive_output(f, opts)
|
|
337
|
+
display(out)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def get_gui(data: pd.DataFrame) -> tuple[widgets.HBox, widgets.Output]:
|
|
341
|
+
"""
|
|
342
|
+
Create GUI for plotting.
|
|
343
|
+
|
|
344
|
+
Attributes:
|
|
345
|
+
data (pd.DataFrame): Input data.
|
|
346
|
+
"""
|
|
347
|
+
# Create sets for system selection
|
|
348
|
+
sets: dict[str, list[str]] = {}
|
|
349
|
+
for setting in settings:
|
|
350
|
+
system_setting = setting.split("/")
|
|
351
|
+
if system_setting[0] in sets:
|
|
352
|
+
sets[system_setting[0]].append(setting)
|
|
353
|
+
else:
|
|
354
|
+
sets[system_setting[0]] = [setting]
|
|
355
|
+
|
|
356
|
+
options_dict = {
|
|
357
|
+
x: widgets.Checkbox(description=x, value=False, style={"description_width": "0px"})
|
|
358
|
+
for x in sorted(list(settings) + list(sets.keys()))
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
ui = multi_checkbox_widget(options_dict)
|
|
362
|
+
|
|
363
|
+
measure_opts = ["time"] + sorted(measures - {"time"}) if "time" in measures else sorted(measures)
|
|
364
|
+
select_measure = widgets.ToggleButtons(
|
|
365
|
+
options=measure_opts,
|
|
366
|
+
description="Measure:",
|
|
367
|
+
disabled=False,
|
|
368
|
+
button_style="", # 'success', 'info', 'warning', 'danger' or ''
|
|
369
|
+
#tooltips=["Cactus plot", "CDF plot"],
|
|
370
|
+
)
|
|
371
|
+
select_merge = widgets.ToggleButtons(
|
|
372
|
+
options=["do not merge", "median", "mean"],
|
|
373
|
+
description="Merge:",
|
|
374
|
+
disabled=False,
|
|
375
|
+
button_style="", # 'success', 'info', 'warning', 'danger' or ''
|
|
376
|
+
tooltips=["Merge runs using median", "Merge runs using mean"],
|
|
377
|
+
)
|
|
378
|
+
select_mode = widgets.ToggleButtons(
|
|
379
|
+
options=["Survivor", "Cactus", "CDF"],
|
|
380
|
+
description="Mode:",
|
|
381
|
+
disabled=False,
|
|
382
|
+
button_style="", # 'success', 'info', 'warning', 'danger' or ''
|
|
383
|
+
tooltips=["Cactus plot", "CDF plot"],
|
|
384
|
+
)
|
|
385
|
+
width_slider = widgets.IntSlider(
|
|
386
|
+
value=1000,
|
|
387
|
+
min=500,
|
|
388
|
+
max=1500,
|
|
389
|
+
step=100,
|
|
390
|
+
orientation="horizontal",
|
|
391
|
+
continuous_update=False,
|
|
392
|
+
)
|
|
393
|
+
height_slider = widgets.IntSlider(
|
|
394
|
+
value=500,
|
|
395
|
+
min=500,
|
|
396
|
+
max=1500,
|
|
397
|
+
step=100,
|
|
398
|
+
orientation="horizontal",
|
|
399
|
+
continuous_update=False,
|
|
400
|
+
)
|
|
401
|
+
sliders = widgets.VBox(
|
|
402
|
+
[
|
|
403
|
+
widgets.Label("Width of the plot in px"),
|
|
404
|
+
width_slider,
|
|
405
|
+
widgets.Label("Height of the plot in px"),
|
|
406
|
+
height_slider,
|
|
407
|
+
]
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
out = widgets.interactive_output(
|
|
411
|
+
plot,
|
|
412
|
+
{
|
|
413
|
+
"measure": select_measure,
|
|
414
|
+
"merge": select_merge,
|
|
415
|
+
"mode": select_mode,
|
|
416
|
+
"width": width_slider,
|
|
417
|
+
"height": height_slider,
|
|
418
|
+
"opts": fixed(options_dict),
|
|
419
|
+
"data": fixed(data),
|
|
420
|
+
"sets": fixed(sets),
|
|
421
|
+
},
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
return (
|
|
425
|
+
widgets.HBox(
|
|
426
|
+
[widgets.VBox([select_measure, select_merge, select_mode, sliders], layout=widgets.Layout(width="60%")), ui]
|
|
427
|
+
),
|
|
428
|
+
out,
|
|
429
|
+
)
|
|
430
|
+
'''
|
|
431
|
+
|
|
432
|
+
plot_heading = """\
|
|
433
|
+
# Plots
|
|
434
|
+
|
|
435
|
+
The first row on the left select which kind of plot will be created.
|
|
436
|
+
|
|
437
|
+
The second row on the left determines how multiple runs (if there are more than 1) will be mergedinto a single result.
|
|
438
|
+
|
|
439
|
+
The sliders can be used to adjust the size of the plot.
|
|
440
|
+
|
|
441
|
+
Finally, select individual settings or all settings of a system to plot using the checkboxes on the right. The input field at the top can be used to search through all possible selections.
|
|
442
|
+
|
|
443
|
+
The scale of the time axis can be selected to the left of the plot.
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
All plots below are interactive. When hovering over a plot, a toolbar will appear, which can be used to zoom, move, and save the plot.
|
|
447
|
+
You can show the full output, without a scrollbar, by clicking the gray bar to the left of the output cell.
|
|
448
|
+
|
|
449
|
+
"""
|
|
450
|
+
plot_code = """\
|
|
451
|
+
gui, out_plot = get_gui(df_fill)
|
|
452
|
+
display(gui)
|
|
453
|
+
display(out_plot)
|
|
454
|
+
"""
|
|
455
|
+
|
|
456
|
+
nb = nbf.v4.new_notebook()
|
|
457
|
+
nb["cells"] = [
|
|
458
|
+
nbf.v4.new_markdown_cell(intro),
|
|
459
|
+
nbf.v4.new_markdown_cell(data_heading),
|
|
460
|
+
nbf.v4.new_code_cell(data_code),
|
|
461
|
+
nbf.v4.new_markdown_cell(funcs_heading),
|
|
462
|
+
nbf.v4.new_code_cell(funcs_code),
|
|
463
|
+
nbf.v4.new_markdown_cell(plot_heading),
|
|
464
|
+
nbf.v4.new_code_cell(plot_code),
|
|
465
|
+
]
|
|
466
|
+
fname = file_name
|
|
467
|
+
nb.cells[1]["metadata"]["jp-MarkdownHeadingCollapsed"] = True
|
|
468
|
+
nb.cells[3]["metadata"]["jp-MarkdownHeadingCollapsed"] = True
|
|
469
|
+
# nb.cells[6]["metadata"]["jupyter"] = {"source_hidden": True}
|
|
470
|
+
|
|
471
|
+
try:
|
|
472
|
+
nbf.validate(nb)
|
|
473
|
+
except nbf.validator.NotebookValidationError as e: # nocoverage
|
|
474
|
+
raise RuntimeError("Generated notebook is invalid") from e
|
|
475
|
+
|
|
476
|
+
with open(fname, "w", encoding="utf-8") as f:
|
|
477
|
+
nbf.write(nb, f)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ODS configuration.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
STYLES_XML = """<?xml version="1.0" encoding="UTF-8"?>
|
|
6
|
+
<office:document-styles
|
|
7
|
+
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
|
8
|
+
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
|
9
|
+
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
|
|
10
|
+
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
|
|
11
|
+
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
|
|
12
|
+
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
|
|
13
|
+
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
14
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
15
|
+
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
|
|
16
|
+
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
|
|
17
|
+
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
|
|
18
|
+
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
|
|
19
|
+
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
|
|
20
|
+
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
|
|
21
|
+
xmlns:math="http://www.w3.org/1998/Math/MathML"
|
|
22
|
+
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
|
|
23
|
+
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
|
|
24
|
+
xmlns:ooo="http://openoffice.org/2004/office"
|
|
25
|
+
xmlns:ooow="http://openoffice.org/2004/writer"
|
|
26
|
+
xmlns:oooc="http://openoffice.org/2004/calc"
|
|
27
|
+
xmlns:dom="http://www.w3.org/2001/xml-events"
|
|
28
|
+
xmlns:rpt="http://openoffice.org/2005/report"
|
|
29
|
+
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2"
|
|
30
|
+
xmlns:rdfa="http://docs.oasis-open.org/opendocument/meta/rdfa#"
|
|
31
|
+
office:version="1.2">
|
|
32
|
+
<office:styles>
|
|
33
|
+
<style:style style:name="Default" style:family="table-cell"/>
|
|
34
|
+
<style:style style:name="cellBest" style:family="table-cell" style:parent-style-name="Default">
|
|
35
|
+
<style:table-cell-properties fo:background-color="#00ff00"/>
|
|
36
|
+
</style:style>
|
|
37
|
+
<style:style style:name="cellWorst" style:family="table-cell" style:parent-style-name="Default">
|
|
38
|
+
<style:table-cell-properties fo:background-color="#ff0000"/>
|
|
39
|
+
</style:style>
|
|
40
|
+
</office:styles>
|
|
41
|
+
</office:document-styles>
|
|
42
|
+
"""
|